C SYNMCH--	SYNTAX MATCHER
C
C COPYRIGHT 1980, INFOCOM COMPUTERS AND COMMUNICATIONS, CAMBRIDGE MA. 02142
C ALL RIGHTS RESERVED, COMMERCIAL USAGE STRICTLY PROHIBITED
C WRITTEN BY R. M. SUPNIK
C
C DECLARATIONS
C
C THIS ROUTINE DETAILS ON BIT 4 OF PRSFLG
C
	LOGICAL FUNCTION SYNMCH()
	IMPLICIT INTEGER(A-Z)
	LOGICAL SYNEQL,TAKEIT
#include "parser.h"
#include "vocab.h"
#include "debug.h"
C
C   THE FOLLOWING DATA STATEMENT WAS ORIGINALLY:
C
C	DATA R50MIN/1RA/
C
	DATA R50MIN/1600/
C
	SYNMCH=.FALSE.
#ifdef debug
	DFLAG=and(PRSFLG, 16).NE.0
	if(dflag) write(0,*) "synflags=",sdir,sind,sstd,sflip,sdriv,svmask
#endif
	J=ACT
C						!SET UP PTR TO SYNTAX.
	DRIVE=0
C						!NO DEFAULT.
	DFORCE=0
C						!NO FORCED DEFAULT.
	QPREP=and(OFLAG,OPREP)
100	J=J+2
C						!FIND START OF SYNTAX.
	IF((VVOC(J).LE.0).OR.(VVOC(J).GE.R50MIN)) GO TO 100
	LIMIT=J+VVOC(J)+1
C						!COMPUTE LIMIT.
	J=J+1
C						!ADVANCE TO NEXT.
C
200	CALL UNPACK(J,NEWJ)
C						!UNPACK SYNTAX.
#ifdef debug
	IF(DFLAG) PRINT 60,O1,P1,DOBJ,DFL1,DFL2
#ifdef NOCC
60	FORMAT('SYNMCH INPUTS TO SYNEQL- ',5I7)
#else NOCC
60	FORMAT(' SYNMCH INPUTS TO SYNEQL- ',5I7)
#endif NOCC
#endif
	SPREP=and(DOBJ,VPMASK)
	IF(.NOT.SYNEQL(P1,O1,DOBJ,DFL1,DFL2)) GO TO 1000
#ifdef debug
	IF(DFLAG) PRINT 60,O2,P2,IOBJ,IFL1,IFL2
#endif
	SPREP=and(IOBJ,VPMASK)
	IF(SYNEQL(P2,O2,IOBJ,IFL1,IFL2)) GO TO 6000
C
C SYNTAX MATCH FAILS, TRY NEXT ONE.
C
	IF(O2) 3000,500,3000
C						!IF O2=0, SET DFLT.
1000	IF(O1) 3000,500,3000
C						!IF O1=0, SET DFLT.
500	IF((QPREP.EQ.0).OR.(QPREP.EQ.SPREP)) DFORCE=J
C						!IF PREP MCH.
	IF((and(VFLAG,SDRIV)).NE.0) DRIVE=J
3000	J=NEWJ
	IF(J.LT.LIMIT) GO TO 200
C						!MORE TO DO?
C SYNMCH, PAGE 2
C
C MATCH HAS FAILED.  IF DEFAULT SYNTAX EXISTS, TRY TO SNARF
C ORPHANS OR GWIMS, OR MAKE NEW ORPHANS.
C
#ifdef debug
	IF(DFLAG) PRINT 20,DRIVE,DFORCE
#ifdef NOCC
20	FORMAT('SYNMCH, DRIVE=',2I6)
#else NOCC
20	FORMAT(' SYNMCH, DRIVE=',2I6)
#endif NOCC
#endif
	IF(DRIVE.EQ.0) DRIVE=DFORCE
C						!NO DRIVER? USE FORCE.
	IF(DRIVE.EQ.0) GO TO 10000
C						!ANY DRIVER?
	CALL UNPACK(DRIVE,DFORCE)
C						!UNPACK DFLT SYNTAX.
C
C TRY TO FILL DIRECT OBJECT SLOT IF THAT WAS THE PROBLEM.
C
	IF((and(VFLAG,SDIR).EQ.0).OR.(O1.NE.0)) GO TO 4000
C
C FIRST TRY TO SNARF ORPHAN OBJECT.
C
	O1=and(OFLAG,OSLOT)
	IF(O1.EQ.0) GO TO 3500
C						!ANY ORPHAN?
	IF(SYNEQL(P1,O1,DOBJ,DFL1,DFL2)) GO TO 4000
C
C ORPHAN FAILS, TRY GWIM.
C
3500	O1=GWIM(DOBJ,DFW1,DFW2)
C						!GET GWIM.
#ifdef debug
	IF(DFLAG) PRINT 30,O1
#ifdef NOCC
30	FORMAT('SYNMCH- DO GWIM= ',I6)
#else NOCC
30	FORMAT(' SYNMCH- DO GWIM= ',I6)
#endif NOCC
#endif debug
	IF(O1.GT.0) GO TO 4000
C						!TEST RESULT.
	CALL ORPHAN(-1,ACT,0,and(DOBJ,VPMASK),0)
	CALL RSPEAK(623)
	RETURN
C
C TRY TO FILL INDIRECT OBJECT SLOT IF THAT WAS THE PROBLEM.
C
4000	IF((and(VFLAG,SIND).EQ.0).OR.(O2.NE.0)) GO TO 6000
	O2=GWIM(IOBJ,IFW1,IFW2)
C						!GWIM.
#ifdef debug
	IF(DFLAG) PRINT 40,O2
#ifdef NOCC
40	FORMAT('SYNMCH- IO GWIM= ',I6)
#else NOCC
40	FORMAT(' SYNMCH- IO GWIM= ',I6)
#endif NOCC
#endif debug
	IF(O2.GT.0) GO TO 6000
	IF(O1.EQ.0) O1=and(OFLAG,OSLOT)
	CALL ORPHAN(-1,ACT,O1,and(DOBJ,VPMASK),0)
	CALL RSPEAK(624)
	RETURN
C
C TOTAL CHOMP
C
10000	CALL RSPEAK(601)
C						!CANT DO ANYTHING.
	RETURN
C SYNMCH, PAGE 3
C
C NOW TRY TO TAKE INDIVIDUAL OBJECTS AND
C IN GENERAL CLEAN UP THE PARSE VECTOR.
C
6000	IF(and(VFLAG,SFLIP).EQ.0) GO TO 5000
	J=O1
C						!YES.
	O1=O2
	O2=J
C
5000	PRSA=and(VFLAG,SVMASK)
	PRSO=O1
C						!GET DIR OBJ.
	PRSI=O2
C						!GET IND OBJ.
	IF(.NOT.TAKEIT(PRSO,DOBJ)) RETURN
C						!TRY TAKE.
	IF(.NOT.TAKEIT(PRSI,IOBJ)) RETURN
C						!TRY TAKE.
	SYNMCH=.TRUE.
#ifdef debug
	IF(DFLAG) PRINT 50,SYNMCH,PRSA,PRSO,PRSI,ACT,O1,O2
#ifdef NOCC
50	FORMAT('SYNMCH- RESULTS ',L1,6I7)
#else NOCC
50	FORMAT(' SYNMCH- RESULTS ',L1,6I7)
#endif NOCC
#endif
	RETURN
C
	END
C UNPACK-	UNPACK SYNTAX SPECIFICATION, ADV POINTER
C
C DECLARATIONS
C
	SUBROUTINE UNPACK(OLDJ,J)
	IMPLICIT INTEGER(A-Z)
#include "vocab.h"
#include "parser.h"
C
	DO 10 I=1,11
C						!CLEAR SYNTAX.
	  SYN(I)=0
10	CONTINUE
C
	VFLAG=VVOC(OLDJ)
	J=OLDJ+1
	IF(and(VFLAG,SDIR).EQ.0) RETURN
	DFL1=-1
C						!ASSUME STD.
	DFL2=-1
	IF(and(VFLAG,SSTD).EQ.0) GO TO 100
	DFW1=-1
C						!YES.
	DFW2=-1
	DOBJ=VABIT+VRBIT+VFBIT
	GO TO 200
C
100	DOBJ=VVOC(J)
C						!NOT STD.
	DFW1=VVOC(J+1)
	DFW2=VVOC(J+2)
	J=J+3
	IF(and(DOBJ,VEBIT).EQ.0) GO TO 200
	DFL1=DFW1
C						!YES.
	DFL2=DFW2
C
200	IF(and(VFLAG,SIND).EQ.0) RETURN
	IFL1=-1
C						!ASSUME STD.
	IFL2=-1
	IOBJ=VVOC(J)
	IFW1=VVOC(J+1)
	IFW2=VVOC(J+2)
	J=J+3
	IF(and(IOBJ,VEBIT).EQ.0) RETURN
	IFL1=IFW1
C						!YES.
	IFL2=IFW2
	RETURN
C
	END
C SYNEQL-	TEST FOR SYNTAX EQUALITY
C
C DECLARATIONS
C
	LOGICAL FUNCTION SYNEQL(PREP,OBJ,SPREP,SFL1,SFL2)
	IMPLICIT INTEGER(A-Z)
#include "objects.h"
#include "parser.h"
C
	IF(OBJ.EQ.0) GO TO 100
C						!ANY OBJECT?
	SYNEQL=(PREP.EQ.and(SPREP,VPMASK)).AND.
&		(or(and(SFL1,OFLAG1(OBJ)),
&		  and(SFL2,OFLAG2(OBJ))).NE.0)
	RETURN
C
100	SYNEQL=(PREP.EQ.0).AND.(SFL1.EQ.0).AND.(SFL2.EQ.0)
	RETURN
C
	END
C TAKEIT-	PARSER BASED TAKE OF OBJECT
C
C DECLARATIONS
C
	LOGICAL FUNCTION TAKEIT(OBJ,SFLAG)
	IMPLICIT INTEGER(A-Z)
#include "parser.h"
	COMMON /STAR/ MBASE,STRBIT
#include "gamestate.h"
#include "state.h"
#include "objects.h"
#include "oflags.h"
#include "advers.h"
C TAKEIT, PAGE 2
C
	TAKEIT=.FALSE.
C						!ASSUME LOSES.
	IF((OBJ.EQ.0).OR.(OBJ.GT.STRBIT)) GO TO 4000
C						!NULL/STARS WIN.
	ODO2=ODESC2(OBJ)
C						!GET DESC.
	X=OCAN(OBJ)
C						!GET CONTAINER.
	IF((X.EQ.0).OR.(and(SFLAG,VFBIT).EQ.0)) GO TO 500
	IF(and(OFLAG2(X),OPENBT).NE.0) GO TO 500
	CALL RSPSUB(566,ODO2)
C						!CANT REACH.
	RETURN
C
500	IF(and(SFLAG,VRBIT).EQ.0) GO TO 1000
	IF(and(SFLAG,VTBIT).EQ.0) GO TO 2000
C
C SHOULD BE IN ROOM (VRBIT NE 0) AND CAN BE TAKEN (VTBIT NE 0)
C
	IF(SCHLST(0,0,HERE,0,0,OBJ).LE.0) GO TO 4000
C						!IF NOT, OK.
C
C ITS IN THE ROOM AND CAN BE TAKEN.
C
	IF((and(OFLAG1(OBJ),TAKEBT).NE.0).AND.
&		(and(OFLAG2(OBJ),TRYBT).EQ.0)) GO TO 3000
C
C NOT TAKEABLE.  IF WE CARE, FAIL.
C
	IF(and(SFLAG,VCBIT).EQ.0) GO TO 4000
	CALL RSPSUB(445,ODO2)
	RETURN
C
C 1000--	IT SHOULD NOT BE IN THE ROOM.
C 2000--	IT CANT BE TAKEN.
C
2000	IF(and(SFLAG,VCBIT).EQ.0) GO TO 4000
1000	IF(SCHLST(0,0,HERE,0,0,OBJ).LE.0) GO TO 4000
	CALL RSPSUB(665,ODO2)
	RETURN
C TAKEIT, PAGE 3
C
C OBJECT IS IN THE ROOM, CAN BE TAKEN BY THE PARSER,
C AND IS TAKEABLE IN GENERAL.  IT IS NOT A STAR.
C TAKING IT SHOULD NOT HAVE SIDE AFFECTS.
C IF IT IS INSIDE SOMETHING, THE CONTAINER IS OPEN.
C THE FOLLOWING CODE IS LIFTED FROM SUBROUTINE TAKE.
C
3000	IF(OBJ.NE.AVEHIC(WINNER)) GO TO 3500
C						!TAKE VEHICLE?
	CALL RSPEAK(672)
	RETURN
C
3500	IF(((X.NE.0).AND.(OADV(X).EQ.WINNER)).OR.
&	 ((WEIGHT(0,OBJ,WINNER)+OSIZE(OBJ)).LE.MXLOAD))
&	 GO TO 3700
	CALL RSPEAK(558)
C						!TOO BIG.
	RETURN
C
3700	CALL NEWSTA(OBJ,559,0,0,WINNER)
C						!DO TAKE.
	OFLAG2(OBJ)=or(OFLAG2(OBJ),TCHBT)
	CALL SCRUPD(OFVAL(OBJ))
	OFVAL(OBJ)=0
C
4000	TAKEIT=.TRUE.
C						!SUCCESS.
	RETURN
C
	END
C
C GWIM- GET WHAT I MEAN IN AMBIGOUS SITUATIONS
C
C DECLARATIONS
C
	INTEGER FUNCTION GWIM(SFLAG,SFW1,SFW2)
	IMPLICIT INTEGER(A-Z)
	LOGICAL TAKEIT,NOCARE
#include "parser.h"
	COMMON /STAR/ MBASE,STRBIT
#include "gamestate.h"
#include "objects.h"
#include "oflags.h"
#include "advers.h"
C GWIM, PAGE 2
C
	GWIM=-1
C						!ASSUME LOSE.
	AV=AVEHIC(WINNER)
	NOBJ=0
	NOCARE=and(SFLAG,VCBIT).EQ.0
C
C FIRST SEARCH ADVENTURER
C
	IF(and(SFLAG,VABIT).NE.0)
&		NOBJ=FWIM(SFW1,SFW2,0,0,WINNER,NOCARE)
	IF(and(SFLAG,VRBIT).NE.0) GO TO 100
50	GWIM=NOBJ
	RETURN
C
C ALSO SEARCH ROOM
C
100	ROBJ=FWIM(SFW1,SFW2,HERE,0,0,NOCARE)
	IF(ROBJ) 500,50,200
C						!TEST RESULT.
C
C ROBJ > 0
C
200	IF((AV.EQ.0).OR.(ROBJ.EQ.AV).OR.
&		(and(OFLAG2(ROBJ),FINDBT).NE.0)) GO TO 300
	IF(OCAN(ROBJ).NE.AV) GO TO 50
C						!UNREACHABLE? TRY NOBJ
300	IF(NOBJ.NE.0) RETURN
C						!IF AMBIGUOUS, RETURN.
	IF(.NOT.TAKEIT(ROBJ,SFLAG)) RETURN
C						!IF UNTAKEABLE, RETURN
	GWIM=ROBJ
500	RETURN
C
	END
