/* C declarations */ %{ #include #include #include #include #include #include #include "debug.h" #include "SyntaxTree.h" #include "SymbolTable.h" #include "Node.h" #include "messages.h" #include "coercion.h" #include "lookup.h" /* Prototypes */ static void yyerror(const char *); /* Import from comp.l */ extern int yylex(void); /* Lexer function */ extern int lineno; /* Current line number */ extern string lastID; /* The most recently read ID */ extern string lastNUM; /* The most recently read value expression */ extern string lastOP; /* The most recently read MULOP or RELOP */ /* Other declarations */ SyntaxTree * tree; /* The syntax tree */ SymbolTable * symtab; /* The symbol table */ string mainScopeName; /* The name of the main scope */ Messages messages; /* Keeps track of warning/error messages */ #ifdef DEBUG int msglevel = 90; /* higher = more debugging messages */ #else int msglevel = 0; /* don't bother sensitive souls */ #endif /* Macro to allow pretty display of parser tree calling stack debug print calls */ #define pdebug(x) pmesg(100, "Parser: '"); pmesg(100, x); pmesg(100, "'\n") %} /* Start symbol */ %start program /* Tokens */ %token PROGRAM ID VAR NUM INTEGER REAL FUNCTION PROCEDURE %token PASCALBEGIN /* BEGIN is used internally by flex :-( */ %token END ADDOP ASSIGNOP IF THEN ELSE WHILE DO RELOP %token MULOP NOT PROG_PARAMETER IRRELEVANT %token UMINUS /* unary minus */ /* We wish to pass Node, Symbols and ReturnType pointers between the rules and * actions */ %union { Node *node; ReturnType returntype; Symbol *symbol; } %expect 1 /* shift/reduce conflict: dangling ELSE */ %% /* GRAMMAR RULES AND ACTIONS */ program: PROGRAM ID { pdebug("program: PROGRAM ID"); /* The program name has just been read; save it */ mainScopeName = lastID; /* Put the program name into the syntax tree */ tree->SetProgramName (mainScopeName); /* Create a new scope in the symbol table */ symtab->AddScope (mainScopeName); /* Add builtin functions and procedures */ /* function readinteger() : integer; */ Symbol * freshFunction = new Symbol_Subprogram(); freshFunction->SetName("readinteger"); freshFunction->SetReturnType(RT_INT); freshFunction->SetSymbolType(ST_FUNCTION); freshFunction->SetLine(0); symtab->AddSymbol(freshFunction); /* procedure writeinteger(i: integer); */ freshFunction = new Symbol_Subprogram(); freshFunction->SetName("writeinteger"); freshFunction->SetReturnType(RT_VOID); freshFunction->SetSymbolType(ST_PROCEDURE); freshFunction->SetLine(0); Symbol * freshParam = new Symbol(); freshParam->SetReturnType(RT_INT); freshParam->SetName("i"); freshFunction->AddParameter(freshParam); symtab->AddSymbol(freshFunction); /* function readreal() : real; */ freshFunction = new Symbol_Subprogram(); freshFunction->SetName("readreal"); freshFunction->SetReturnType(RT_REAL); freshFunction->SetSymbolType(ST_FUNCTION); freshFunction->SetLine(0); symtab->AddSymbol(freshFunction); /* procedure writereal(r: real); */ freshFunction = new Symbol_Subprogram(); freshFunction->SetName("writereal"); freshFunction->SetReturnType(RT_VOID); freshFunction->SetSymbolType(ST_PROCEDURE); freshFunction->SetLine(0); freshParam = new Symbol(); freshParam->SetReturnType(RT_REAL); freshParam->SetName("r"); freshFunction->AddParameter(freshParam); symtab->AddSymbol(freshFunction); } ';' declarations subprogram_declarations compound_statement '.' { tree->SetProgramBody($7); } ; type_identifier_list: ',' ID { /* Create new symbol */ check_id(lastID); Symbol * freshVar = new Symbol(); symtab->AddSymbol(freshVar); /* Fill with yet known values */ freshVar->SetSymbolType(ST_UNKNOWN); freshVar->SetName(lastID); freshVar->SetLine(lineno); $$ = tree->CreateLeaf(freshVar); } type_identifier_list { pdebug("type_identifier_list: ',' ID type_identifier_list"); $3->GetSymbol()->SetReturnType($4->GetReturnType()); /* Create list out of it */ $$ = tree->CreateParentNode(NODE_ID, $4->GetReturnType(), $3, $4); //XXX: Check: NODE_ID that's not a leaf? } | ':' type { pdebug("type_identifier_list: ':' type"); /* Closing of list is a Node of type NODE_EMPTY */ Node * freshNode = tree->CreateLeaf(); freshNode->SetReturnType($2); $$ = freshNode; } ; declarations: /* In declarations the VAR-variables are listed for the program as well as for the procedures and functions. */ declarations VAR ID { pdebug("declarations: declarations VAR ID"); /* Create new symbol */ check_id(lastID); Symbol * freshVar = new Symbol(); symtab->AddSymbol(freshVar); /* Fill with yet known values */ freshVar->SetSymbolType(ST_UNKNOWN); freshVar->SetName(lastID); freshVar->SetLine(lineno); /* Temporary fill first Node with leaf value, as official value is not yet known */ $$ = tree->CreateParentNode(NODE_ID, RT_UNKNOWN, tree->CreateLeaf(freshVar), tree->CreateLeaf()); } type_identifier_list ';' { pdebug("declarations: type_identifier_list ';'"); /* Fix temporary node */ Node * ptrNode = $4; ptrNode->SetReturnType($5->GetReturnType()); ptrNode->GetLeftChild()->GetSymbol()->SetReturnType($5->GetReturnType()); ptrNode->SetRightChild($5); /* Set all symbols to be parameters */ while ( ptrNode->GetNodeType() != NODE_EMPTY ) { ptrNode->GetLeftChild()->GetSymbol()->SetSymbolType(ST_VARIABLE); ptrNode = ptrNode->GetRightChild(); } $$ = $4; } | /* lambda */ { pdebug("declarations: "); $$ = tree->CreateLeaf() ; } ; type: standard_type { pdebug("type: standard_type"); $$ = $1; } ; standard_type: INTEGER { pdebug("standard_type: INTEGER"); $$ = RT_INT; } | REAL { pdebug("standard_type: REAL"); $$ = RT_REAL; } ; subprogram_declarations: subprogram_declarations subprogram_declaration ';' { pdebug("subprogram_declaration: subprogram_declarations subprogram_declarations ';'"); /* Empty, no actions required */ } | /* lambda */ { pdebug("subprogram_declarations: "); /* Empty, no actions required */ } ; subprogram_declaration: subprogram_head declarations compound_statement { pdebug("subprogram_declaration: subprogram_head declarations compound_statement"); tree->AddSubprogram($1->GetName(), $3); // leave subprogram scope symtab->SetCurrentScope(symtab->GetRootScope()->GetName()); } ; subprogram_head: FUNCTION ID { pdebug("subprogram_head: FUNCTION ID"); check_id(lastID); /* Create New subprogram */ Symbol * freshProgram = new Symbol_Subprogram(); freshProgram->SetLine(lineno); freshProgram->SetName(lastID); freshProgram->SetSymbolType(ST_FUNCTION); symtab->AddSymbol(freshProgram); /* Subprogram means new scope */ symtab->AddScope(lastID); symtab->SetCurrentScope(lastID); Node * freshNode = tree->CreateLeaf(freshProgram); /* Push fresh function into passing variable */ $$ = freshNode; } arguments ':' standard_type ';' { pdebug("subprogram_head: arguments ':' standard_type ';'"); /* Set returntype of new function */ Node * ptrNode = $3; Symbol * ptrSymbol = ptrNode->GetSymbol(); ptrNode->SetReturnType($6); ptrSymbol->SetReturnType($6); /* Add parameters to new function */ Node * ptrNodeParam; ptrNode = $4; while (ptrNode->GetNodeType() != NODE_EMPTY) { ptrNodeParam = ptrNode->GetLeftChild(); while (ptrNodeParam->GetNodeType() != NODE_EMPTY) { ptrSymbol->AddParameter(ptrNodeParam->GetLeftChild()->GetSymbol()); ptrNodeParam = ptrNodeParam->GetRightChild(); } ptrNode = ptrNode->GetRightChild(); } $$ = $3->GetSymbol(); } | PROCEDURE ID { pdebug("subprogram_head: PROCEDURE ID"); /* Looks a bit like a FUNCTION ID clone, but got subtle * differences in arguments and return values */ check_id(lastID); /* Procedure mean new subprogram */ Symbol * freshProgram = new Symbol_Subprogram(); freshProgram->SetLine(lineno); freshProgram->SetName(lastID); freshProgram->SetSymbolType(ST_PROCEDURE); freshProgram->SetReturnType(RT_VOID); symtab->AddSymbol(freshProgram); /* Procedure mean new scope */ symtab->AddScope(lastID); symtab->SetCurrentScope(lastID); Node * freshNode = tree->CreateLeaf(freshProgram); freshNode->SetReturnType(RT_VOID); $$ = freshNode; } arguments ';' { pdebug("subprogram_head: arguments ';'"); /* Add parameters to procedure */ Node * ptrNode = $4; Node * ptrNodeParam; Symbol * ptrSymbol = $3->GetSymbol(); while (ptrNode->GetNodeType() != NODE_EMPTY) { ptrNodeParam = ptrNode->GetLeftChild(); while (ptrNodeParam->GetNodeType() != NODE_EMPTY) { ptrSymbol->AddParameter(ptrNodeParam->GetLeftChild()->GetSymbol()); ptrNodeParam = ptrNodeParam->GetRightChild(); } ptrNode = ptrNode->GetRightChild(); } $$ = $3->GetSymbol(); } ; arguments: '(' parameter_lists ')' { pdebug("arguments: '(' parameter_lists ')'"); $$ = $2; } | /* lambda */ { pdebug("arguments: "); $$ = tree->CreateLeaf(); } ; parameter_lists: parameter_list ';' parameter_lists { pdebug("parameter_lists: parameter_lists ';' parameter_lists"); $$ = tree->CreateParentNode(NODE_UNKNOWN, RT_VOID, $1, $3); } | parameter_list { pdebug("parameter_lists: parameter_list"); $$ = tree->CreateParentNode(NODE_UNKNOWN, RT_VOID, $1, tree->CreateLeaf()); } ; parameter_list: ID { pdebug("parameter_list: ID"); /* Create new symbol */ check_id(lastID); Symbol * freshVar = new Symbol(); symtab->AddSymbol(freshVar); /* Fill with yet known values */ freshVar->SetSymbolType(ST_UNKNOWN); freshVar->SetName(lastID); freshVar->SetLine(lineno); /* Temporary add leaf as end node, not yet fully fillable */ $$ = tree->CreateParentNode(NODE_ID, RT_UNKNOWN, tree->CreateLeaf(freshVar), tree->CreateLeaf()); } type_identifier_list { pdebug("parameter_list: type_identifier_list"); /* Fill missing (returnType) information */ Node * ptrNode = $2; ptrNode->SetReturnType($3->GetReturnType()); ptrNode->GetLeftChild()->GetSymbol()->SetReturnType($3->GetReturnType()); ptrNode->SetRightChild($3); /* Set all symbols to be parameters */ while ( ptrNode->GetNodeType() != NODE_EMPTY ) { ptrNode->GetLeftChild()->GetSymbol()->SetSymbolType(ST_PARAMETER); ptrNode = ptrNode->GetRightChild(); } $$ = $2; } ; compound_statement: PASCALBEGIN optional_statements END { pdebug("compound_statement: PASCALBEGIN optional_statements END"); $$ = $2; } ; optional_statements: statement_list { pdebug("optional_statements: statement_list"); $$ = $1; } | /* lambda */ { pdebug("optional_statements: "); $$ = tree->CreateLeaf(); } ; statement_list: statement { pdebug("statement_list: statement"); $$ = tree->CreateParentNode(NODE_STATEMENT_LIST, RT_VOID, $1, tree->CreateLeaf()); } | statement_list ';' statement { pdebug("statement_list: statement_list ';' statement"); /* Make sure statements, get appended the right way e.g. * always rightmost of the list */ /* Find the last statement list */ Node *statement_list = $1; while (statement_list->GetRightChild()->GetNodeType() != NODE_EMPTY) { statement_list = statement_list->GetRightChild(); } /* Replace empty node with new statement list */ Node *new_statement_list = tree->CreateParentNode(NODE_STATEMENT_LIST, RT_VOID, $3, statement_list->GetRightChild()); statement_list->SetRightChild(new_statement_list); $$ = $1; } ; statement: variable ASSIGNOP expression { pdebug("statement: variable ASSIGNOP expression"); ReturnType returntype = $1->GetReturnType(); $$ = tree->CreateParentNode(NODE_ASSIGNMENT, returntype, $1, coerce(returntype, $3)); } | procedure_statement { pdebug("statement: procedure_statement"); $$ = $1; } | compound_statement { pdebug("statement: compound_statement"); $$ = $1; } | IF boollikeexp THEN statement optional_else_statement { pdebug("statement: IF boollikeexp THEN statement optional_else_statement"); if ($5->GetNodeType() == NODE_EMPTY) { /* No ELSE part */ $$ = tree->CreateParentNode(NODE_IF, RT_VOID, $2, $4); } else { $$ = tree->CreateParentNode(NODE_IF, RT_VOID, $2, tree->CreateParentNode(NODE_IF_TARGETS, RT_VOID, $4, $5)); } } | WHILE boollikeexp DO statement { pdebug("statement: WHILE boollikeexp DO statement"); $$ = tree->CreateParentNode(NODE_WHILE, RT_VOID, $2, $4); } ; optional_else_statement: ELSE statement { pdebug("optional_else_statement: ELSE statement"); $$ = $2; } | /* lambda */ { pdebug("optional_else_statement: "); $$ = tree->CreateLeaf(); } ; variable: ID { pdebug("variable: ID"); /* Find ID in symbol table */ Symbol *symbol = lookup(lastID, ST_VARIABLE); /* symbol found: make sure it is a variable or a function return value */ SymbolType symboltype = symbol->GetSymbolType(); bool isvariable = (symboltype == ST_VARIABLE || symboltype == ST_PARAMETER); bool isfuncretval = (symboltype == ST_FUNCTION && symtab->GetCurrentScopeName() == lastID); if ( !isvariable && !isfuncretval ) { messages.LValueError(lineno, lastID); } $$ = tree->CreateLeaf(symbol); } ; procedure_statement: ID { pdebug("procedure_statement: ID"); /* Lookup ID */ Symbol *symbol = lookup(lastID, ST_PROCEDURE); /* check the type of the symbol */ Node *node = NULL; switch (symbol->GetSymbolType()) { case ST_FUNCTION: node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(), tree->CreateLeaf(symbol), tree->CreateLeaf()); messages.ReturnValueError(lineno, lastID, symbol->GetReturnType()); check_parameters(node); break; case ST_PROCEDURE: node = tree->CreateParentNode(NODE_PROCCALL, RT_VOID, tree->CreateLeaf(symbol), tree->CreateLeaf()); check_parameters(node); break; case ST_VARIABLE: /* fall through */ case ST_PARAMETER: case ST_UNKNOWN: case ST_ERROR: case ST_PROGRAM: case ST_TEMPVAR: case ST_LABEL: default: messages.CallError(lineno, lastID, symbol->GetSymbolType()); /* return dummy NODE_EMPTY, to avoid freeze/crashing tree */ node = tree->CreateLeaf(); } assert(node != NULL); $$ = node; } | ID { /* Lookup ID */ $$ = lookup(lastID, ST_PROCEDURE); } '(' expression_list ')' { pdebug("procedure_statement: ID '(' expression_list ')'"); /* check the type of the symbol */ Symbol *symbol = $2; Node *node = NULL; switch (symbol->GetSymbolType()) { case ST_FUNCTION: node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(), tree->CreateLeaf(symbol), $4); messages.ReturnValueError(lineno, lastID, symbol->GetReturnType()); check_parameters(node); break; case ST_PROCEDURE: node = tree->CreateParentNode(NODE_PROCCALL, symbol->GetReturnType(), tree->CreateLeaf(symbol), $4); check_parameters(node); break; case ST_VARIABLE: /* fall through */ case ST_PARAMETER: case ST_UNKNOWN: case ST_ERROR: case ST_PROGRAM: case ST_TEMPVAR: case ST_LABEL: default: messages.CallError(lineno, symbol->GetName(), symbol->GetSymbolType()); /* return dummy NODE_EMPTY, to avoid freeze/crashing tree */ node = tree->CreateLeaf(); } assert(node != NULL); $$ = node; } ; expression_list: expression { pdebug("expression_list: expression"); $$ = tree->CreateParentNode(NODE_EXPRLIST, RT_VOID, $1, tree->CreateLeaf()); } | expression ',' expression_list { pdebug("expression_list: expression ',' expression_list"); $$ = tree->CreateParentNode(NODE_EXPRLIST, RT_VOID, $1, $3); } ; boollikeexp: expression RELOP expression { pdebug("boollikeexp: expression RELOP expression"); ReturnType returnType = minimumtype($1->GetReturnType(), $3->GetReturnType()); Node *node_relop = NULL; /* Find proper nodeType = mapping lastOP 1:1 NODE_* */ NodeType nodeType = NODE_UNKNOWN; if (lastOP == "=") { nodeType = NODE_REL_EQUAL; } else if (lastOP == "<") { nodeType = NODE_REL_LT; } else if (lastOP == ">") { nodeType = NODE_REL_GT; } else if (lastOP == "<=") { nodeType = NODE_REL_LTE; } else if (lastOP == ">=") { nodeType = NODE_REL_GTE; } else if (lastOP == "<>") { nodeType = NODE_REL_NOTEQUAL; } node_relop = tree->CreateParentNode(nodeType, RT_BOOL, coerce(returnType, $1), coerce(returnType, $3)); $$ = tree->CreateParentNode(NODE_BOOLEXPR, RT_BOOL, node_relop); } | '(' boollikeexp ')' { pdebug("boollikeexp: '(' boollikeexp ')'"); /* to allow stuff like "if (a > 3) then" */ $$ = $2; } ; expression: simple_expression { pdebug("expression: simple_expression"); $$ = $1; } ; simple_expression: term { pdebug("simple_expression: term"); $$ = $1; } | signplus term { pdebug("simple_expression: signplus term"); $$ = tree->CreateParentNode(NODE_SIGNMINUS, $2->GetReturnType(), $2); } | signminus term { pdebug("simple_expression: signminus term"); $$ = tree->CreateParentNode(NODE_SIGNPLUS, $2->GetReturnType(), $2); } | simple_expression '+' term { pdebug("simple_expression: simple_expression '+' term"); ReturnType returnType = minimumtype($1->GetReturnType(), $3->GetReturnType()); $$ = tree->CreateParentNode(NODE_ADD, returnType, coerce(returnType, $1), coerce(returnType, $3)); } | simple_expression '-' term { pdebug("simple_expression: simple_expression '-' term"); ReturnType returnType = minimumtype($1->GetReturnType(), $3->GetReturnType()); $$ = tree->CreateParentNode(NODE_SUB, returnType, coerce(returnType, $1), coerce(returnType, $3)); } | simple_expression ADDOP term { pdebug("simple_expression: simple_expression ADDOP term"); /* According to ../tests/varia/no_real_in_boolean_expr.p1 no * reals allowed in boolean expressions, so set returnType and coerce will TypeError */ ReturnType returnType = RT_INT; $$ = tree->CreateParentNode(NODE_OR, returnType, coerce(returnType, $1), coerce(returnType, $3)); } ; term: factor { pdebug("term: factor"); $$ = $1; } | term MULOP factor { pdebug("term: term MULOP factor"); ReturnType returnType = minimumtype($1->GetReturnType(), $3->GetReturnType()); if (lastOP == "*") { $$ = tree->CreateParentNode(NODE_MUL, returnType, coerce(returnType, $1), coerce(returnType, $3)); } else if (lastOP == "/") { // real division operator always returns real $$ = tree->CreateParentNode(NODE_DIV, RT_REAL, coerce(RT_REAL, $1), coerce(RT_REAL, $3)); } else if (lastOP == "div") { // integer division operator always returns integer $$ = tree->CreateParentNode(NODE_IDIV, RT_INT, coerce(RT_INT, $1), coerce(RT_INT, $3)); } else if (lastOP == "mod") { // only works on integers $$ = tree->CreateParentNode(NODE_MOD, RT_INT, coerce(RT_INT, $1), coerce(RT_INT, $3)); } else if (lastOP == "and") { /* Bitwise operator, not allowed on reals, coerce will TypeError */ returnType = RT_INT; $$ = tree->CreateParentNode(NODE_AND, returnType, coerce(returnType, $1), coerce(returnType, $3)); } } ; factor: ID { pdebug("factor: ID"); /* Lookup ID */ Symbol *symbol = lookup(lastID, ST_VARIABLE); /* check the type of the symbol */ Node *node = NULL; switch (symbol->GetSymbolType()) { case ST_VARIABLE: /* fall through */ case ST_PARAMETER: node = tree->CreateLeaf(symbol); break; case ST_FUNCTION: node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(), tree->CreateLeaf(symbol), tree->CreateLeaf()); check_parameters(node); break; case ST_PROCEDURE: /* fall through */ case ST_UNKNOWN: case ST_ERROR: case ST_PROGRAM: case ST_TEMPVAR: case ST_LABEL: default: messages.RValueError(lineno, lastID, symbol->GetSymbolType()); /* return dummy NODE_EMPTY, to avoid crashing/freezing tree */ node = tree->CreateLeaf(); } assert(node != NULL); $$ = node; } | ID { /* Lookup ID */ $$ = lookup(lastID, ST_FUNCTION); } '(' expression_list ')' { pdebug("factor: ID '(' expression_list ')'"); /* check the type of the symbol */ Node *node = NULL; Symbol *symbol = $2; switch (symbol->GetSymbolType()) { case ST_FUNCTION: node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(), tree->CreateLeaf(symbol), $4); check_parameters(node); break; case ST_PROCEDURE: node = tree->CreateParentNode(NODE_PROCCALL, symbol->GetReturnType(), tree->CreateLeaf(symbol), $4); check_parameters(node); break; case ST_VARIABLE: /* fall through */ case ST_PARAMETER: case ST_UNKNOWN: case ST_ERROR: case ST_PROGRAM: case ST_TEMPVAR: case ST_LABEL: default: messages.CallError(lineno, symbol->GetName(), symbol->GetSymbolType()); /* return dummy NODE_EMPTY, to avoid crashing/freezing tree */ node = tree->CreateLeaf(); } assert(node != NULL); $$ = node; } | NUM { pdebug("factor: NUM"); /* XXX: Hack to find out whether value is set to be real or * integer, should really be something which needs to be done * by the lexer, but we are not allowed to alter the language * during this assignment */ if (lastNUM.find_first_of(".E") != string::npos) { /* found real */ float value = atof(lastNUM.c_str()); $$ = tree->CreateLeaf(value); } else { /* found integer */ int value = atoi(lastNUM.c_str()); $$ = tree->CreateLeaf(value); } } | '(' expression ')' { pdebug("factor: '(' expression ')'"); $$ = $2; } | NOT factor { pdebug("factor: NOT factor"); /* Bitwise operator, no real allowed, coerce will TypeError */ ReturnType returnType = RT_INT; $$ = tree->CreateParentNode(NODE_NOT, returnType, coerce(returnType, $2)); } ; signplus: '+' { pdebug("signplus: '+'"); } ; signminus: '-' %prec UMINUS { pdebug("signminus: '-' \%prec UMINUS"); } ; %% /* End of rules, more C code will follow now */ void initialize() { /* Create & initialize the abstract data structures */ tree = new SyntaxTree; symtab = new SymbolTable; } void cleanup() { /* Free objects */ delete tree; delete symtab; } /* Nice usage warning, for the ones in need */ void usage() { fprintf(stderr, "Arguments:\n"); fprintf(stderr, "-v[vv] = more verbose output\n"); fprintf(stderr, "-q[qq] = less verbose output\n"); fprintf(stderr, "-w = turn on warning messages\n"); fprintf(stderr, "-n = turn off warning messages\n"); fprintf(stderr, "-h = usage\n"); exit(EX_USAGE); } int main(int argc, char * argv[]) { int parseResult; int ch; /* Set trace settings */ while ((ch = getopt(argc, argv, "hnqvw")) != -1) { switch (ch) { case 'v': msglevel += 30; break; case 'q': msglevel -= 30; break; case 'w': messages.EnableWarnings(); break; case 'n': messages.DisableWarnings(); break; case 'h': default: usage(); } } initialize(); /* Start the parsing procedure */ parseResult = yyparse(); messages.ShowNumbers(); /* Dump the syntax tree & symbol table */ tree->Dump (stdout); printf("\n"); symtab->Dump (stdout); cleanup(); /* Return the exit code. Note that the exit code does not depend on * parseResult only, but also on the result of your semantic checks */ return (parseResult == 0 && messages.GetErrors() == 0) ? 0 : 1; } static void yyerror(const char *s) { fprintf(stderr, "line %d: %s\n", lineno, s); } int yywrap() { return(1); }