/* S T A T E M E N T S */ { #include #include #include #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); if (options['g']) { static int ms_lineno; if (ms_lineno != dot.tk_lineno) { C_ms_std((char *) 0, N_SLINE, dot.tk_lineno); ms_lineno = dot.tk_lineno; } } } [ 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); } | 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); } 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); } ; /* 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); } 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); } ]? ]? ;