*Important:* Do `make clean` to work around a problem and prevent infinite rebuilds, https://github.com/davidgiven/ack/issues/68 I edit tokens.g in util/LLgen/src, so I regenerate tokens.c. The regeneration script bootstrap.sh can't find LLgen, but I can run the same command by typing the path to llgen.
		
			
				
	
	
		
			476 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			476 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
/* S T A T E M E N T S */
 | 
						|
{
 | 
						|
#include	<string.h>
 | 
						|
#include    "parameters.h"
 | 
						|
#include	<alloc.h>
 | 
						|
#include	<em.h>
 | 
						|
#include	<stb.h>
 | 
						|
 | 
						|
#include	"LLlex.h"
 | 
						|
#include	"chk_expr.h"
 | 
						|
#include	"def.h"
 | 
						|
#include	"desig.h"
 | 
						|
#include	"f_info.h"
 | 
						|
#include	"idf.h"
 | 
						|
#include	"main.h"
 | 
						|
#include	"misc.h"
 | 
						|
#include	"node.h"
 | 
						|
#include	"scope.h"
 | 
						|
#include	"type.h"
 | 
						|
 | 
						|
int slevel = 0;		/* nesting level of statements */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ISO section 6.8.3.2, p. 128 */
 | 
						|
CompoundStatement:
 | 
						|
	BEGIN StatementSequence END
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.1, p. 128 */
 | 
						|
StatementSequence:
 | 
						|
	Statement
 | 
						|
	[ %persistent
 | 
						|
		';' Statement
 | 
						|
	]*
 | 
						|
					{ chk_labels(slevel + 1); }
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.1, p. 126 */
 | 
						|
Statement
 | 
						|
{
 | 
						|
	struct node *nd;
 | 
						|
} :
 | 
						|
					{
 | 
						|
					  slevel++;
 | 
						|
					}
 | 
						|
	[ Label(&nd) ':'
 | 
						|
					{ if( nd ) DefLabel(nd, slevel); }
 | 
						|
	]?
 | 
						|
					{ if( !options['L'] )
 | 
						|
						C_lin((arith) dot.tk_lineno);
 | 
						|
#ifdef DBSYMTAB
 | 
						|
					  if (options['g']) {
 | 
						|
					    static int ms_lineno;
 | 
						|
 | 
						|
					    if (ms_lineno != dot.tk_lineno) {
 | 
						|
						C_ms_std((char *) 0, N_SLINE, (int) dot.tk_lineno);
 | 
						|
						ms_lineno = dot.tk_lineno;
 | 
						|
					    }
 | 
						|
					  }
 | 
						|
#endif /* DBSYMTAB */
 | 
						|
					}
 | 
						|
	[
 | 
						|
		SimpleStatement
 | 
						|
	|
 | 
						|
		StructuredStatement
 | 
						|
	]
 | 
						|
					{ slevel--; }
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.2.1, p. 126 */
 | 
						|
SimpleStatement
 | 
						|
{
 | 
						|
	struct node *pnd, *expp;
 | 
						|
	unsigned short line;
 | 
						|
} :
 | 
						|
	/* This is a changed rule, because the grammar as specified in the
 | 
						|
	 * reference is not LL(1), and this gives conflicts.
 | 
						|
	 * Note : the grammar states : AssignmentStatement |
 | 
						|
	 *				ProcedureStatement | ...
 | 
						|
	 * In order to add assertions, there is an extra entry, which gives
 | 
						|
	 * a conflict. This conflict is then resolved using an %if clause.
 | 
						|
	 */
 | 
						|
	EmptyStatement
 | 
						|
|
 | 
						|
	GotoStatement
 | 
						|
|
 | 
						|
	/* Evidently this is the beginning of the changed part
 | 
						|
	 */
 | 
						|
	%if( !options['s'] && !strcmp(dot.TOK_IDF->id_text, "assert") )
 | 
						|
	IDENT			{ line = LineNumber; }
 | 
						|
		Expression(&expp)
 | 
						|
				{ AssertStat(expp, line);
 | 
						|
				  FreeNode(expp);
 | 
						|
				}
 | 
						|
|
 | 
						|
	IDENT			{ pnd = MkLeaf(Name, &dot); }
 | 
						|
	[	%default
 | 
						|
 | 
						|
		/* At this point the IDENT can be a FunctionIdentifier in
 | 
						|
		 * which case the VariableAccessTail must be empty.
 | 
						|
		 */
 | 
						|
		VariableAccessTail(&pnd)
 | 
						|
		[
 | 
						|
			%default
 | 
						|
			BECOMES
 | 
						|
		|
 | 
						|
			'='	{ error("':=' expected instead of '='"); }
 | 
						|
		]
 | 
						|
		Expression(&expp)
 | 
						|
				{ AssignStat(pnd, expp); }
 | 
						|
	|
 | 
						|
				{ pnd = MkNode(Call, pnd, NULLNODE, &dot); }
 | 
						|
		ActualParameterList(&(pnd->nd_right))?
 | 
						|
				{ ProcStat(pnd);
 | 
						|
 | 
						|
				  if( !err_occurred )
 | 
						|
					CodeCall(pnd);
 | 
						|
 | 
						|
				  FreeNode(pnd);
 | 
						|
				}
 | 
						|
 | 
						|
	]
 | 
						|
|
 | 
						|
	InputOutputStatement
 | 
						|
	/* end of changed part
 | 
						|
	 */
 | 
						|
;
 | 
						|
 | 
						|
InputOutputStatement
 | 
						|
{
 | 
						|
	struct node *nd = NULLNODE;
 | 
						|
} :
 | 
						|
	/* This is a new rule because the grammar specified by the standard
 | 
						|
	 * is not exactly LL(1) (see SimpleStatement).
 | 
						|
	 */
 | 
						|
	[
 | 
						|
		READ ReadParameterList(&nd)		{ ChkRead(nd); }
 | 
						|
	|
 | 
						|
		READLN ReadParameterList(&nd)?		{ ChkReadln(nd); }
 | 
						|
	|
 | 
						|
		WRITE WriteParameterList(&nd)		{ ChkWrite(nd); }
 | 
						|
	|
 | 
						|
		WRITELN WriteParameterList(&nd)?	{ ChkWriteln(nd); }
 | 
						|
	]
 | 
						|
							{ FreeNode(nd); }
 | 
						|
;
 | 
						|
 | 
						|
EmptyStatement:
 | 
						|
	/* empty */
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.1, p. 128 */
 | 
						|
StructuredStatement:
 | 
						|
	CompoundStatement
 | 
						|
|
 | 
						|
	ConditionalStatement
 | 
						|
|
 | 
						|
	RepetitiveStatement
 | 
						|
|
 | 
						|
	WithStatement
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.2.4, p. 127 */
 | 
						|
GotoStatement
 | 
						|
{
 | 
						|
	struct node *nd;
 | 
						|
} :
 | 
						|
	GOTO Label(&nd)
 | 
						|
					{ if( nd ) TstLabel(nd, slevel); }
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.3, p. 128 */
 | 
						|
ConditionalStatement:
 | 
						|
	%default
 | 
						|
	CaseStatement
 | 
						|
|
 | 
						|
	IfStatement
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.6, p. 129 */
 | 
						|
RepetitiveStatement:
 | 
						|
	RepeatStatement
 | 
						|
|
 | 
						|
	WhileStatement
 | 
						|
|
 | 
						|
	ForStatement
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.10, p. 132 */
 | 
						|
WithStatement
 | 
						|
{
 | 
						|
	struct scopelist *Save = CurrVis;
 | 
						|
	struct node *nd;
 | 
						|
} :
 | 
						|
	WITH
 | 
						|
	RecordVariableList(&nd)
 | 
						|
	DO
 | 
						|
	Statement	{ EndWith(Save, nd);
 | 
						|
			  chk_labels(slevel + 1);
 | 
						|
			}
 | 
						|
;
 | 
						|
 | 
						|
RecordVariableList(register struct node **pnd;)
 | 
						|
{
 | 
						|
	struct node *nd;
 | 
						|
} :
 | 
						|
	RecordVariable(&nd)
 | 
						|
				{ *pnd = nd = MkNode(Link, nd, NULLNODE, &dot);
 | 
						|
				  nd->nd_symb = ',';
 | 
						|
				}
 | 
						|
	[ %persistent
 | 
						|
		','		{ nd->nd_right = MkLeaf(Link, &dot);
 | 
						|
				  nd = nd->nd_right;
 | 
						|
				}
 | 
						|
		RecordVariable(&(nd->nd_left))
 | 
						|
	]*
 | 
						|
;
 | 
						|
 | 
						|
RecordVariable(register struct node **pnd;):
 | 
						|
	VariableAccess(pnd)
 | 
						|
				{ WithStat(*pnd); }
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.4, p. 128 */
 | 
						|
IfStatement
 | 
						|
{
 | 
						|
	struct node *nd;
 | 
						|
	label l1 = ++text_label;
 | 
						|
	label l2 = ++text_label;
 | 
						|
} :
 | 
						|
	IF
 | 
						|
	BooleanExpression(&nd)
 | 
						|
					{ struct desig ds;
 | 
						|
					
 | 
						|
					  ds = InitDesig;
 | 
						|
					  if( !err_occurred )
 | 
						|
						CodeExpr(nd, &ds, l1);
 | 
						|
					  FreeNode(nd);
 | 
						|
					}
 | 
						|
	THEN
 | 
						|
	Statement			{ chk_labels(slevel + 1); }
 | 
						|
	[ %prefer	/* closest matching */
 | 
						|
		ELSE
 | 
						|
					{ C_bra(l2);
 | 
						|
					  C_df_ilb(l1);
 | 
						|
					}
 | 
						|
		Statement
 | 
						|
					{ C_df_ilb(l2);
 | 
						|
					  chk_labels(slevel + 1);
 | 
						|
					}
 | 
						|
	|
 | 
						|
		/* empty */
 | 
						|
					{ C_df_ilb(l1); }
 | 
						|
	]
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.5, p. 128 */
 | 
						|
CaseStatement
 | 
						|
{
 | 
						|
	struct node *casend, *nd;
 | 
						|
	label exit_label;
 | 
						|
} :
 | 
						|
	/* This is a changed rule, because the grammar as specified in the
 | 
						|
	 * reference states that a semicolon is optional before END,
 | 
						|
	 * and this is not LL(1).
 | 
						|
	 */
 | 
						|
	CASE				{ casend = nd = MkLeaf(Link, &dot);
 | 
						|
					  casend->nd_lab = ++text_label;
 | 
						|
					  exit_label = ++text_label;
 | 
						|
					}
 | 
						|
	Expression(&(nd->nd_left))
 | 
						|
					{ CaseExpr(casend); }
 | 
						|
	OF
 | 
						|
	CaseListElement(&(nd->nd_right), exit_label)
 | 
						|
					{ nd = nd->nd_right; }
 | 
						|
	CaseListElementTail(&(nd->nd_right), exit_label)
 | 
						|
	END
 | 
						|
					{ CaseEnd(casend, exit_label); }
 | 
						|
;
 | 
						|
 | 
						|
CaseListElementTail(register struct node **pnd; label exit_label;):
 | 
						|
	/* This is a new rule, all because of a silly semicolon
 | 
						|
	 */
 | 
						|
	/* empty */
 | 
						|
|
 | 
						|
%default
 | 
						|
	';'
 | 
						|
	[
 | 
						|
		/* empty */
 | 
						|
	|
 | 
						|
		CaseListElement(pnd, exit_label)
 | 
						|
		CaseListElementTail(&((*pnd)->nd_right), exit_label)
 | 
						|
	]
 | 
						|
;
 | 
						|
 | 
						|
CaseListElement(register struct node **pnd; label exit_label;):
 | 
						|
	CaseConstantList(pnd)
 | 
						|
	':'
 | 
						|
				{ *pnd = MkNode(Link, *pnd, NULLNODE, &dot);
 | 
						|
				  (*pnd)->nd_lab = ++text_label;
 | 
						|
				  C_df_ilb(text_label);
 | 
						|
				}
 | 
						|
	Statement		{ C_bra(exit_label);
 | 
						|
				  chk_labels(slevel + 1);
 | 
						|
				}
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.7, p. 129 */
 | 
						|
RepeatStatement
 | 
						|
{
 | 
						|
	struct node *nd;
 | 
						|
	label repeatlb = ++text_label;
 | 
						|
} :
 | 
						|
	REPEAT
 | 
						|
					{ C_df_ilb(repeatlb); }
 | 
						|
	StatementSequence
 | 
						|
	UNTIL
 | 
						|
	BooleanExpression(&nd)
 | 
						|
					{ struct desig ds;
 | 
						|
 | 
						|
					  ds = InitDesig;
 | 
						|
					  if( !err_occurred )
 | 
						|
						CodeExpr(nd, &ds, repeatlb);
 | 
						|
					  FreeNode(nd);
 | 
						|
					}
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.8, p. 129 */
 | 
						|
WhileStatement
 | 
						|
{
 | 
						|
	struct node *nd;
 | 
						|
	label whilelb = ++text_label;
 | 
						|
	label exitlb = ++text_label;
 | 
						|
 | 
						|
} :
 | 
						|
	WHILE
 | 
						|
					{ C_df_ilb(whilelb); }
 | 
						|
	BooleanExpression(&nd)
 | 
						|
					{ struct desig ds;
 | 
						|
 | 
						|
					  ds = InitDesig;
 | 
						|
					  if( !err_occurred )
 | 
						|
						CodeExpr(nd, &ds, exitlb);
 | 
						|
					  FreeNode(nd);
 | 
						|
					}
 | 
						|
	DO
 | 
						|
	Statement
 | 
						|
					{ C_bra(whilelb);
 | 
						|
					  C_df_ilb(exitlb);
 | 
						|
					  chk_labels(slevel + 1);
 | 
						|
					}
 | 
						|
;
 | 
						|
 | 
						|
/* ISO section 6.8.3.9, p. 130 */
 | 
						|
ForStatement
 | 
						|
{
 | 
						|
	register struct node *nd;
 | 
						|
	int stepsize;
 | 
						|
	label l1 = ++text_label;
 | 
						|
	label l2 = ++text_label;
 | 
						|
	arith tmp2 = (arith) 0;
 | 
						|
} :
 | 
						|
	FOR
 | 
						|
	/* ControlVariable must be an EntireVariable */
 | 
						|
	IDENT			{ nd = MkLeaf(Name, &dot); }
 | 
						|
	BECOMES
 | 
						|
	Expression(&(nd->nd_left))
 | 
						|
	[
 | 
						|
		TO		{ stepsize = 1; }
 | 
						|
	|
 | 
						|
		DOWNTO		{ stepsize = -1; }
 | 
						|
	]
 | 
						|
	Expression(&(nd->nd_right))
 | 
						|
				{ ChkForStat(nd);
 | 
						|
				  if( !err_occurred )	{
 | 
						|
					CodePExpr(nd->nd_left);
 | 
						|
					C_dup(int_size);
 | 
						|
					tmp2 = CodeInitFor(nd->nd_right, 2);
 | 
						|
				  	CodeFor(nd, stepsize, l1, l2);
 | 
						|
				  }
 | 
						|
				}
 | 
						|
	DO
 | 
						|
	Statement
 | 
						|
				{ if( !err_occurred )
 | 
						|
				       CodeEndFor(nd, stepsize, l1, l2, tmp2);
 | 
						|
				  EndForStat(nd);
 | 
						|
				  chk_labels(slevel + 1);
 | 
						|
				  FreeNode(nd);
 | 
						|
				  if( tmp2 ) FreeInt(tmp2);
 | 
						|
				}
 | 
						|
;
 | 
						|
 | 
						|
/* SPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIALSPECIAL */
 | 
						|
/* ISO section 6.9, p. 132-136 */
 | 
						|
ReadParameterList(register struct node **pnd;)
 | 
						|
{
 | 
						|
	register struct node *nd;
 | 
						|
} :
 | 
						|
	/* This is a changed rule, because the grammar as specified in the
 | 
						|
	 * reference is not LL(1), and this gives conflicts.
 | 
						|
	 */
 | 
						|
	'('
 | 
						|
		VariableAccess(pnd)	/* possibly a FileVariable */
 | 
						|
					{ *pnd = nd =
 | 
						|
					     MkNode(Link, *pnd, NULLNODE, &dot);
 | 
						|
					  nd->nd_symb = ',';
 | 
						|
					}
 | 
						|
		[ %persistent
 | 
						|
			',' 		{ nd->nd_right = MkLeaf(Link, &dot);
 | 
						|
					  nd = nd->nd_right;
 | 
						|
					}
 | 
						|
			VariableAccess(&(nd->nd_left))
 | 
						|
		]*
 | 
						|
	')'
 | 
						|
;
 | 
						|
 | 
						|
WriteParameterList(register struct node **pnd;)
 | 
						|
{
 | 
						|
	register struct node *nd;
 | 
						|
} :
 | 
						|
	/* This is a changed rule, because the grammar as specified in the
 | 
						|
	 * reference is not LL(1), and this gives conflicts.
 | 
						|
	 */
 | 
						|
	'('
 | 
						|
		/* Only the first WriteParameter can be a FileVariable !!
 | 
						|
		 */
 | 
						|
		WriteParameter(pnd)
 | 
						|
					{ *pnd = nd =
 | 
						|
					     MkNode(Link, *pnd, NULLNODE, &dot);
 | 
						|
					  nd->nd_symb = ',';
 | 
						|
					}
 | 
						|
		[ %persistent
 | 
						|
			',' 		{ nd->nd_right = MkLeaf(Link, &dot);
 | 
						|
					  nd = nd->nd_right;
 | 
						|
					}
 | 
						|
			WriteParameter(&(nd->nd_left))
 | 
						|
		]*
 | 
						|
	')'
 | 
						|
;
 | 
						|
 | 
						|
WriteParameter(register struct node **pnd;)
 | 
						|
{
 | 
						|
	register struct node *nd;
 | 
						|
} :
 | 
						|
	Expression(pnd)
 | 
						|
					{ if( !ChkExpression(*pnd) )
 | 
						|
						(*pnd)->nd_type = error_type;
 | 
						|
					  MarkUsed(*pnd);
 | 
						|
					  *pnd = nd =
 | 
						|
					     MkNode(Link, *pnd, NULLNODE, &dot);
 | 
						|
					  nd->nd_symb = ':';
 | 
						|
					}
 | 
						|
	[
 | 
						|
	/* Here the first Expression can't be a FileVariable
 | 
						|
	 */
 | 
						|
		':'			{ nd->nd_right = MkLeaf(Link, &dot);
 | 
						|
					  nd = nd->nd_right;
 | 
						|
					}
 | 
						|
		Expression(&(nd->nd_left))
 | 
						|
					{ if( !ChkExpression(nd->nd_left) )
 | 
						|
					      nd->nd_left->nd_type = error_type;
 | 
						|
					  MarkUsed(nd->nd_left);
 | 
						|
					}
 | 
						|
		[
 | 
						|
			':'		{ nd->nd_right = MkLeaf(Link, &dot);
 | 
						|
					  nd = nd->nd_right;
 | 
						|
					}
 | 
						|
			Expression(&(nd->nd_left))
 | 
						|
					{ if( !ChkExpression(nd->nd_left) )
 | 
						|
					      nd->nd_left->nd_type = error_type;
 | 
						|
					  MarkUsed(nd->nd_left);
 | 
						|
					}
 | 
						|
		]?
 | 
						|
	]?
 | 
						|
;
 |