   program := block* EOF

   block := IF if-block
	  | FOR for-block
	  | % comp-dir
	  | stmt

   compdir := %INCLUDE ( numlit minus numlit )? STRLIT?

   ifblock := IF relexp thengo eoln block* ( ELSE eoln block* )? END IF
	    | IF relexp thengo if-tail

   forblock := FOR numadr equals numexp TO numexp ( STEP numexp )? eoln
	       block* NEXT numadr

   stmt := DATA data-stmt
	 | DEF def-stmt
	 | END
	 | REM rem-stmt
	 | RFORM rform-stmt
	 | eoln
	 | imp-stmt

   imp-stmt := BLOCK blkio-stmt
	  | BREAK
	  | BYE
	  | ( CHAIN | SWAP ) chain-stmt
	  | CLOSE close-stmt
	  | DEBUG debug-stmt
	  | DELAY procall
	  | DELETE del-stmt
	  | DELREC procall
	  | DIM dim-stmt
	  | EXTRACT procall
	  | GETREC procall
	  | GOTO go-stmt
	  | GOSUB go-stmt
	  | IF if-stmt
	  | ( INPUT | TINPUT) input-stmt
	  | ( KADD| KDEL | KFIND | KNEXT ) procall
	  | LOCK procall
	  | LOPEN lopen-stmt
	  | LREAD lread-stmt
	  | LWRITE lwrite-stmt
	  | NEW
	  | ON on-stmt
	  | OPEN open-stmt
	  | PACK pack-stmt
	  | POSITION posfilstmt
	  | PRINT print-stmt
	  | ( QADD | QSUB | QMUL | QDIV | QLOAD | QSTORE ) procall
	  | RANDOMIZE
	  | READ read-stmt
	  | RENAME rename-stmt
	  | REPLACE procall
	  | RESTORE rest-stmt
	  | RETURN
	  | SAVE procall
	  | ( STMA | STMB | STMC ) stmcall
	  | ( SCANWHILE | SCANUNTIL ) procall
	  | STOP
	  | STRPOS procall
	  | ( SCANWHILE | SCANUNTIL | EXTRACT ) procall
	  | SYSTEM procall
	  | TRACE trace-stmt
	  | UNLOCK procall
	  | UNPACK unpack-stmt
	  | VALUE procall
	  | WRITE write-stmt
	  | XCALL stmcall
	  | LET let-stmt
	  | let-stmt
  
   chainstmt := ( CHAIN | SWAP ) strexp (thengo line-number)?
  
   debugstmt := DEBUG ( ON | OFF )
  
   delstmt := errvar strexp
  
   errvar := ( numvar comma )?
  
   dimstmt := DIM dimvar ( comma dimvar )*
   dimvar  := numvar open subscript close
	    | strvar open number close
  
   letstmt := numadr equals numexp
	    | numadr comma mulnlet
	    | strvar equals strletexp
	    | strvar comma mulslet
  
   mulnlet := numadr ( comma numadr )* equals numexp
  
   strletexp  := strletitem ( comma strletitem )*
   strletitem := string-function open explist close | expression
  
   mulslet := strvar ( comma strvar )* equals strletexp
  
   packstmt := PACK (strexp | line-number) comma strvar (comma expression)*
  
   unpackstmt := UNPACK (strexp | line-number) comma strexp (comma (numvar | strvar) )*
  
   renamestmt := RENAME errvar strexp comma strexp
  
   reststmt := RESTORE number?
  
   gostmt := GOTO number
	   | GOSUB number
  
   ifstmt := IF relexp thengo if-tail
  
   iftail := ( line-number | imp-stmt )
	     ( ELSE ( GOTO? line-number | imp-stmt ) )?
  
   on-stmt := ON ( ERR | IKEY ) onerrtail 
	    | ON numexp thengo ( linelist | GOSUB linelist )
 onerrtail := thengo (line-number | INT | imp-stmt)
  linelist := line-number ( comma line-number )*
  
   thengo := GOTO line-number
	   | THEN GOTO line-number
	   | THEN line-number
	   | THEN 
	   | {not a line-number or eoln}
returns with token = NUMLIT if any of first three forms found
  
   tracestmt := TRACE ON ( FILE filespec )?
	      | TRACE OFF
   blkiostmt := BLOCK ( READ | WRITE ) ( FILE filespec )? (strvar | arraydesc)
  
   readstmt := READ ( FILE filespec )? varlist
   varlist  := (numvar | strvar) ( comma (numvar | strvar) )*
  
   writestmt := WRITE FILE filespec explist
   explist := expresion ( comma expression )*
  
   lopenstmt := LOPEN errvar FILE ( lparen | lbrack ) numexp comma lopentail
   lopentail := strvar ( comma numexp )? ( rparen | rbrack ) comma strexp
	      | numexp ( comma numexp )? ( rparen | rbrack ) comma strexp comma
		strexp comma numexp ( comma numexp ( comma numexp 
		( comma numexp ( comma numexp )? )? )? )?
  
   lreadstmt := LREAD FILE filespec comma strvar
  
   lwritestmt := LWRITE FILE filespec comma strexp
  
   closestmt := CLOSE (FILE filespec)?
  
   openstmt := OPEN errvar FILE filespec strexp
  
   posfilstmt := POSITION FILE filespec
  
   input-stmt := ( INPUT | TINPUT numexp comma) (FILE filespec)?
		 (USING strexp comma)? inarglist semicolon?
   inarglist  := inargelem ( comma inargelem )*
   inargelem  := strlit | strvar | numadr | @termcntrl
  
   print-stmt := PRINT (FILE filespec)? print-list
               | PRINT (FILE filespec)? USING strexp comma explist?
   print-list := ( prntelem? ( comma | semicolon) )* prntelem?
   prntelem   := @termcntrl | ( TAB open numexp close ) | expression
  
   termcntrl := @ open expression ( comma expression )? close
  
   filespec := FILE (open | lbrack) explist (close | rbrack)
  
   numadr := numvar subscript?
  
   smpadr := numvar
  
   relexp := numexp ( relop numexp )?
           | strexp relop strexp
  
   expression := numexp | strexp
  
   numexp := ( plus | minus )? term ( plus | minus ) term
  
   term := factor ( ( asterisk | slash ) factor )*
  
   factor := primary ( up-arrow primary )*
  
   primary := numvar subscript?
	    | numlit
	    | open numexp close
	    | numeric-function open explist close
	    | FNCNAM open numexp close
  
   numcon := numlit
  
   strexp := strlit
	   | strvar
  
   strvar := strnam subscript?
  
   subscript := open numexp ( comma numexp )? close
  
