(* General disclaimer.
	The following is a Llama description file for the language
pl0 as described in Wirth's A + D = P.  It was not originally
designed to illustrate compiler implementation and follows Wirth's
implementation very closely, using many of the same variables
and procedures.
	The above is to explain away such cryptic variable names
as "cx", "dx", "tx" etc.  They are certainly not there as an
example of commendable programming practice.  Please do not copy
me -- "do as I say not what I do".
	Also some details of the implementation would be
handled differently in an independent implementation -- for
example the use of the global variable "dx".
*)
&term
	NUL,LETTER,DIGIT,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,ODDSYM,
	EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,RPAREN,COMMA,SEMICOLON,
	PERIOD,BECOMES,BEGINSYM,ENDSYM,IFSYM,THENSYM,
	WHILESYM,DOSYM,CALLSYM,CONSTSYM,VARSYM,PROCSYM
&left TIMES SLASH
&left PLUS MINUS
&non EQL NEQ LSS LEQ GTR GEQ
&gram
programme	   = proghead block PERIOD.
proghead	   = (*empty*)				   
					&( tx := 0;	lev := 0 )&
		   .
block		   = blockhead statement		   
					&( gen(opr,0,0);  tx := $1.tx0 )&
		   .
blockhead	   = startofblock
		     constdeclarations
		     vardeclarations
		     procdeclarations			   
					&(
					   with table[$1.blocktx] do
					     begin fixup(adr);	adr := cx;  size:= $3.dx end;
					   gen(int,0,dx);
					   $$.tx0 := $1.blocktx
					)&
		   .
startofblock	   = (*empty*)				   
					&(
					   table[tx].adr := cx;	 dx := 3;
					   gen(jmp,0,0);  $$.blocktx := tx
					)&
		   .
constdeclarations  = CONSTSYM constdeflist SEMICOLON
		   | (*empty*).
constdeflist	   = constdeflist COMMA constdef
		   | constdef.
constdef	   = IDENT EQL NUMBER			   
					&( enter(constobj,$1.id,$3.num) )&
		   .
vardeclarations	   = VARSYM vardeflist SEMICOLON	   
					&($$.dx := dx)&
		   | (*empty*)				   
					&($$.dx := dx)&
		   .
vardeflist	   = vardeflist COMMA vardef
		   | vardef.
vardef		   = IDENT				   
					&( enter(varobj,$1.id,0) )&
		   .
procdeclarations   = procdeflist SEMICOLON
		   | (*empty*).
procdeflist	   = procdeflist SEMICOLON procdef
		   | procdef.
procdef		   = prochead block			   
					&( lev := lev-1 )&
		   .
prochead	   = PROCSYM IDENT SEMICOLON		   
					&( enter(procobj,$2.id,0);  lev := lev+1; )&
		   .
statement	   = variable BECOMES expression	   
					&( assign($1.vartx) )&
		   | CALLSYM IDENT			   
					&( proccall($2.id) )&
		   | ifcondition statement		   
					&( fixup($1.ifjpc) )&
		   | whilehead whilecondition statement	   
					&(
					   gen(jmp,0,$1.whileentry);
					   fixup($2.whilejpc)
					)&
		   | BEGINSYM statementlist ENDSYM
		   | (*empty*).
variable	   = IDENT				   
					&( $$.vartx := checkid($1.id,[varobj],12) )&
		   .
statementlist	   = statementlist SEMICOLON statement
		   | statement.
ifcondition	   = IFSYM condition THENSYM		   
					&( $$.ifjpc := cx;  gen(jpc,0,0) )&
		   .
whilehead	   = WHILESYM				   
					&( $$.whileentry := cx )&
		   .
whilecondition	   = condition DOSYM			   
					&( $$.whilejpc := cx;  gen(jpc,0,0) )&
		   .
condition	   = ODDSYM expression			   
					&( gen(opr,0,6) )&
		   | expression EQL expression		   
					&( gen(opr,0,8) )&
		   | expression NEQ expression		   
					&( gen(opr,0,9) )&
		   | expression LSS expression		   
					&( gen(opr,0,10) )&
		   | expression GEQ expression		   
					&( gen(opr,0,11) )&
		   | expression GTR expression		   
					&( gen(opr,0,12) )&
		   | expression LEQ expression		   
					&( gen(opr,0,13) )&
		   .
expression	   = PLUS term
		   | MINUS term				   
					&( gen(opr,0,1) )&
		   | term.
term		   = term PLUS term			   
					&( gen(opr,0,2) )&
		   | term MINUS term			   
					&( gen(opr,0,3) )&
		   | term TIMES term			   
					&( gen(opr,0,4) )&
		   | term SLASH term			   
					&( gen(opr,0,5) )&
		   | LPAREN expression RPAREN
		   | IDENT				   
					&( loadvalue($1.id) )&
		   | NUMBER				   
					&( loadliteral($1.num) )&.
&prog
program pl0r(input,output);
(*pl/0 compiler with code generation*)
&const
#include "pl0r.consts.i"
&type
  llvaltype = record
	      case llsymbol of
		NUMBER: (num: integer);
		IDENT: (id: alfa);
		blockhead: (tx0: integer);
		startofblock: (blocktx: integer);
		vardeclarations: (dx: integer);
		variable: (vartx: integer);
		ifcondition: (ifjpc: integer);
		whilehead: (whileentry: integer);
		whilecondition: (whilejpc: integer);
	      end;
#include "pl0r.types.i"
&var
#include #pl0r.vars.i"
&proc
#include "pl0r.procs.i"
&main
begin (*main program*)
  init;
  llparser;
end.
