[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Nov 28 19:31:59 1995 
Subject:Patterns for use with lvars (was reporting pop bugs (and pvars)) 
From:Aaron Sloman 
Volume-ID:951129.05 

ianr@cogs.susx.ac.uk (Ian Rogers) writes:

> Date: 27 Nov 1995 16:10:32 GMT
> Organization: University of Sussex
>
> A.Sloman@uk.ac.bham.cs wrote:
> ....
> > It's even worse to make the change and then leave lots of libraries and
> > documentation that are then broken.
>
> Absolutely. It wouldn't have been hard to search all the libraries and put
>
> 	compile_mode :pop11 +oldvar;
>
> at the head of each file that used the matcher.

Unfortunately that would not fix all the teaching documentation. I
think I'd have to search through about 3 Megabytes of stuff and I am
far too busy with other things. Besides which there are printed
versions....

> The correct solution is to fix the matcher to recognise lvars.

Here's a first simple shot at that. This works with the ordinary
Pop-11 matcher, but only in V15.0 because of the extension to valof.
Ignore the references to doesmatch. You can simply compile the
following and then try out the examples given.
===================================================================

/* --- The University of Birmingham 1995.  --------------------------------
 > File:            $poplocal/local/lib/readpattern.p
 > Purpose:         Read in a pattern, changing variables to idents
 > 					Define new syntax word "!" for this purpose
 > Author:          Aaron Sloman, Nov 26 1995 (see revisions)
 > Documentation:	See HELP * DOESMATCH
 > Related Files:   LIB * DOESMATCH, LIB * FMATCHES,
 */


/*
    ![ .... ]
        creates a new type of pattern structure for use with lvars, etc.

	![?x ison ??y]

    	creates a list in which the words "x" and "y" are replaced
		by the corresponding current identifiers.

The syntactic operator "!" defined below can ONLY be followed by list
expressions, and it reads them in and replaces occurrences of variable
names after "?" or "??" with identifiers. The resulting list can be used
as a pattern to be given to either the standard pattern matcher (in
Poplog Version 15.0 onwards) or the more general matcher doesmatch,
defined in LIB * DOESMATCH (available from Birmingham).

A pattern read in after "!" works with lexical variables as they are
treated like dynamic variables.

I think it is more efficient to use dlvars than lvars, but am not sure.

Here is an example, which can be tried after compiling this file.

define list_between(item1, item2, list) -> found;
    ;;; Here found is automatically declared as lvars, as are the
    ;;; input variables in Poplog version 15, but just to make
    ;;; the point we declare it

    lvars found;

    unless list matches ![== ^item1 ??found  ^item2 ==] then
        false -> found;
    endunless;

enddefine;

;;; Now test the procedure

vars words = [a b c d e f g];

list_between("a", "g", words) =>
** [b c d e f]
list_between("d", "e", words) =>
** []
list_between("e", "c", words) =>
** <false>

It works also with restriction elements (See HELP * MATCHES).

;;; Mark and load the next two lines together.
lvars x;
[[a b c]] matches ![[== ??x:2]], x =>
** <true> [b c]

;;; Try that without "!"

;;; Or a procedure restriction
lvars n;
[a b c 3 4 d 4 5 e] matches ![== ?n == ?n:isinteger ==], n=>
** <true> 4

;;; Some test cases, showing that in vector expressions the "?" and "??"
;;; are ignored.
vars v1,v2,v3;

! [v1 ?v1 {v2 ?v2 [?v2]} [v3 ?v3]] =>
** [v1 ? <ident <undef v1>> {v2 ? v2 [? v2]} [v3 ? <ident <undef v3>>]]

lvars lv1, lv2, lv3;
! [lv1 ?lv1 {lv2 ?lv2 [?lv2]} [lv3 ?lv3]] =>
** [lv1 ? <ident <undef>> {lv2 ? lv2 [? lv2]} [lv3 ? <ident <undef>>]]

Note: if procedures using patterns created with "!" are traced, then
identifiers will show up in patterns with their current values, not the
names of the identifiers, as here:

lvars lv4 = 99, lv5 = "cat" ;
![lv4 ?lv4 lv5 ?lv5] =>
** [lv4 ? <ident 99> lv5 ? <ident cat>]

WARNING:
	Patterns should NOT contain evaluated sub-expressions quoting
	"?" or "??", e.g.

		![== [?x b] == [?x h ^(consword("?" >< 'foo')] ==], x =>

	Finally note that patterns containing lexically scoped variables
	cannot be compiled as constants. (See LIB * COMPILE_MODE)
*/

compile_mode: pop11 +strict;

#_INCLUDE '$usepop/pop/lib/include/pop11_flags.ph'
#_INCLUDE '$usepop/pop/lib/include/vm_flags.ph'

section;

applist([! where readpattern sysPUSHQ], sysunprotect);

lvars procedure oldPUSHQ;

define lconstant Readpattern();

	;;; Read in a list or vector expression minus the closing bracket,
	;;; replacing words following "?", "??", and ":" with the corresponding
	;;; identifier, in nested lists, but not inside nested vectors.

	dlvars
		was_query = false,
		in_vector = iscaller(nonsyntax {);

	;;; It would be nice to make patterns constants where possible,
	dlocal pop_pop11_flags = pop_pop11_flags || POP11_CONSTRUCTOR_CONSTS;

	;;; Discount lexical idents pushed in patterns. I.e. don't treat as type 3
	;;; See REF * VMCODE, and REF * pop_vm_flags
	;;; IS THIS SAFE ???? A.S. Nov 1995
	dlocal pop_vm_flags = pop_vm_flags || VM_DISCOUNT_LEX_PROC_PUSHES;

	dlocal oldPUSHQ;
	if isundef(oldPUSHQ) then sysPUSHQ -> oldPUSHQ endif;

	define dlocal sysPUSHQ(item);
		lvars idprops item;

		lvars invec, inlist, inpat;

		if was_query then
			if isword(item) then
				identprops(item) -> idprops;
				if idprops == undef or isinteger(idprops) then
					sysIDENT(item)
				else
					mishap(item, 1, 'UNSUITABLE ITEM AFTER ' sys_>< was_query)
				endif
			elseif was_query == ":" and isinteger(item) then
				oldPUSHQ(item)
			elseif isident(item) then
				oldPUSHQ(item)
			else
				mishap(item, 1, 'NON-WORD AFTER ' sys_>< was_query)
			endif;
			false -> was_query
		else
			oldPUSHQ(item);
;;;; 			Removed the colon. A.S. 29Nov95
;;;;			if lmember(item, #_< [? ?? :] >_#) then
			if lmember(item, #_< [? ?? ] >_#) then
				;;; could the next item be a query variable? Or a restriction
				if lmember(nextreaditem(), #_<[% "]", "}", "%", "^", """ %]>_# ) then
					;;; end of expression
					false;
				elseif in_vector then
					;;; make sure "{" is higher in calling chain than Readpattern
					;;; and that current context is a list expression lower down
					lvars
						invec = iscaller(nonsyntax {),
						inlist = iscaller(nonsyntax [),
						inpat = iscaller(Readpattern);

					(inpat < invec) and (inlist < inpat) and item
				elseif iscaller(nonsyntax {) then
					;;; in an embedded vector
					false
				else
					item
				endif
			else
				false
			endif ->  was_query
		endif
	enddefine;

	;;; Read in the list expression, planting special code
	apply(nonsyntax [)
enddefine;

;;; Prepare for expressions of the form
;;;		![ ....] where <exp>
;;; to be compiled as if written
;;;		(![ ....],  procedure; <exp> endprocedure)

global constant syntax where = pop_undef;

define constant readpattern(trywhere);
	;;; Check that a list expression follows on proglist
	;;; Read in its items using Readpattern to replace variable
	;;; names with identifiers.
	lvars item, trywhere;

	readitem() -> item;
	if item /== "[" then
		mishap(item, 1, 'LIST EXPECTED AFTER "!"')
	endif;

	;;; Now read in the list, replacing pattern variables with
	;;; identifiers
	Readpattern();

	;;; Check if a "where <test> " expression follows. If so compile it as
	;;; procedure; <test> endprocedure; and push the procedure. This is for
	;;; matchers which accept a third argument which is a boolean procedure
	;;; to determine whether a match is successful.

	if trywhere then
		if pop11_try_nextreaditem("where") then
			sysPROCEDURE("where",0);
			;;; Read expression with precedence 11. (It's debatable whether it
			;;; makes syntactic sense to grab operators of higher precedence
			;;; than "!" itself, but it needs to be left this way for backward
			;;; compatibility and allows and/or expresions to be included in the where
			;;; expression.)
			pop11_comp_prec_expr(221,false) ->;
			sysPUSHQ(sysENDPROCEDURE())
		endif
	else
		if nextitem() == "where" then
			mishap('"where" FOUND WHERE NOT PERMITTED', [])
		endif
	endif;
enddefine;

define global syntax 7 ! = readpattern(%true%)
	;;; The precedence must be less than that of doesmatch
enddefine;

applist([! readpattern where sysPUSHQ], sysprotect);

endsection;

===================================================================

Aaron
-- 
Aaron Sloman, ( http://www.cs.bham.ac.uk/~axs )
School of Computer Science, The University of Birmingham, B15 2TT, England
EMAIL   A.Sloman@cs.bham.ac.uk
Phone: +44-121-414-4775 (Sec 3711)       Fax:   +44-121-414-4281