%{ #include #include #include #include "common/common.h" #include "syntax_tree/SyntaxTree.h" #include "lab1_lexical_analyzer/lexical_analyzer.h" // uncomment this to generate tree-generation python files /*#define TREE_GEN_GRAPH*/ /*#define TREE_GEN_TEXT*/ // external functions from lex extern int yylex(); extern int yyparse(); extern int yyrestart(); extern FILE * yyin; // external variables from lexical_analyzer module extern myloc* pmyloc; /*extern int lines;*/ extern char * yytext; // Global syntax tree. SyntaxTree * gt; void yyerror(const char * s); void callback(int p, void* ptr) { #ifdef TREE_GEN_TEXT if (p == 1) { printSyntaxTreeNode(stdout, (SyntaxTreeNode*)ptr, 0); } #endif #ifdef TREE_GEN_GRAPH static FILE* fout; static char* output; static int counter; if (p == 1) { printSyntaxTreeNodeGraphic(fout, (SyntaxTreeNode*)ptr); /*fprintf(fout, "treefromsyntaxtree.get_svg().saveas(\"%s_%d.svg\")\n", output, ++counter);*/ } else if (p == 0) { printf("[DEBUG TREE] start new file...\n"); counter = 0; char outputpathtree[256] = "./treegraph/"; output = ptr; strcat(outputpathtree, output); strcat(outputpathtree, ".py"); printf("[DEBUG TREE] generate python script %s...\n", outputpathtree); fout = fopen(outputpathtree, "w"); fprintf(fout, "#!/usr/bin/env python3\nfrom IPython.core.interactiveshell import InteractiveShell\nInteractiveShell.ast_node_interactivity = \"all\"\nimport svgling\n"); } else if (p == -1) { printf("[DEBUG TREE] done.\n"); fclose(fout); } #endif return; } %} %union { SyntaxTreeNode * node; } %token ERROR ADD SUB MUL DIV LT LTE GT GTE EQ NEQ ASSIN SEMICOLON COMMA LPARENTHESE RPARENTHESE LBRACKET RBRACKET LBRACE RBRACE ELSE IF INT RETURN VOID WHILE ID NUMBER ARRAY LETTER EOL COMMENT BLANK %nonassoc LOWER_THAN_ELSE %nonassoc ELSE /********** TODO: Your token definition here ***********/ /* compulsory starting symbol */ %start program %% /*************** TODO: Your rules here *****************/ program : declaration_list {gt->root = newSyntaxTreeNode("program"); SyntaxTreeNode_AddChild(gt->root, $1);callback(1, $$);} ; declaration_list : declaration_list declaration {$$ = newSyntaxTreeNode("declaration-list"); SyntaxTreeNode_AddChild($$, $1); SyntaxTreeNode_AddChild($$, $2);callback(1, $$);} | declaration {$$ = newSyntaxTreeNode("declaration-list"); SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; declaration : var_declaration {$$ = newSyntaxTreeNode("declaration");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | fun_declaration {$$ = newSyntaxTreeNode("declaration");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; var_declaration : type_specifier ID SEMICOLON {$$ = newSyntaxTreeNode("var-declaration"); SyntaxTreeNode_AddChild($$, $1); SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | type_specifier ID LBRACKET NUMBER RBRACKET SEMICOLON {$$ = newSyntaxTreeNode("var-declaration"); SyntaxTreeNode_AddChild($$, $1); SyntaxTreeNode_AddChild($$, $2); SyntaxTreeNode_AddChild($$, $3); SyntaxTreeNode_AddChild($$, $4);SyntaxTreeNode_AddChild($$, $5);SyntaxTreeNode_AddChild($$, $6);callback(1, $$);} ; type_specifier : INT {$$ = newSyntaxTreeNode("type-specifier"); SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | VOID {$$ = newSyntaxTreeNode("type-specifier"); SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; fun_declaration : type_specifier ID LPARENTHESE params RPARENTHESE compound_stmt {$$ = newSyntaxTreeNode("fun-declaration"); SyntaxTreeNode_AddChild($$, $1); SyntaxTreeNode_AddChild($$, $2); SyntaxTreeNode_AddChild($$, $3); SyntaxTreeNode_AddChild($$, $4); SyntaxTreeNode_AddChild($$, $5); SyntaxTreeNode_AddChild($$, $6);callback(1, $$);} ; params : param_list {$$ = newSyntaxTreeNode("params"); SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | VOID {$$ = newSyntaxTreeNode("params"); SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; param_list : param_list COMMA param {$$ = newSyntaxTreeNode("param-list"); SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | param {$$ = newSyntaxTreeNode("param-list"); SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; param : type_specifier ID {$$ = newSyntaxTreeNode("param");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);callback(1, $$);} | type_specifier ID ARRAY {$$ = newSyntaxTreeNode("param");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} ; compound_stmt : LBRACE local_declarations statement_list RBRACE {$$ = newSyntaxTreeNode("compound-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);SyntaxTreeNode_AddChild($$, $4);callback(1, $$);} ; local_declarations : local_declarations var_declaration {$$ = newSyntaxTreeNode("local-declarations");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);callback(1, $$);} | epsilon {$$ = newSyntaxTreeNode("local-declarations");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; statement_list : statement_list statement {$$ = newSyntaxTreeNode("statement-list");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);callback(1, $$);} | epsilon {$$ = newSyntaxTreeNode("statement-list");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; statement: expression_stmt {$$ = newSyntaxTreeNode("statement");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | compound_stmt {$$ = newSyntaxTreeNode("statement");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | selection_stmt {$$ = newSyntaxTreeNode("statement");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | iteration_stmt {$$ = newSyntaxTreeNode("statementt");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | return_stmt {$$ = newSyntaxTreeNode("statement");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; expression_stmt : expression SEMICOLON {$$ = newSyntaxTreeNode("expression-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);callback(1, $$);} | SEMICOLON {$$ = newSyntaxTreeNode("expression-stmt");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; selection_stmt : IF LPARENTHESE expression RPARENTHESE statement %prec LOWER_THAN_ELSE {$$ = newSyntaxTreeNode("selection-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);SyntaxTreeNode_AddChild($$, $4);SyntaxTreeNode_AddChild($$, $5);callback(1, $$);} | IF LPARENTHESE expression RPARENTHESE statement ELSE statement {$$ = newSyntaxTreeNode("selection-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);SyntaxTreeNode_AddChild($$, $4);SyntaxTreeNode_AddChild($$, $5);SyntaxTreeNode_AddChild($$, $6);SyntaxTreeNode_AddChild($$, $7);callback(1, $$);} ; iteration_stmt : WHILE LPARENTHESE expression RPARENTHESE statement {$$ = newSyntaxTreeNode("iteration-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);SyntaxTreeNode_AddChild($$, $4);SyntaxTreeNode_AddChild($$, $5);callback(1, $$);} ; return_stmt : RETURN SEMICOLON {$$ = newSyntaxTreeNode("return-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);callback(1, $$);} | RETURN expression SEMICOLON {$$ = newSyntaxTreeNode("return-stmt");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} ; expression : var ASSIN expression {$$ = newSyntaxTreeNode("expression");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | simple_expression {$$ = newSyntaxTreeNode("expression");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; var : ID {$$ = newSyntaxTreeNode("var");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | ID LBRACKET expression RBRACKET {$$ = newSyntaxTreeNode("var");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);SyntaxTreeNode_AddChild($$, $4);callback(1, $$);} ; simple_expression : additive_expression relop additive_expression {$$ = newSyntaxTreeNode("simple-expression");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | additive_expression {$$ = newSyntaxTreeNode("simple-expression");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; relop : LTE {$$ = newSyntaxTreeNode("relop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | LT {$$ = newSyntaxTreeNode("relop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | GT {$$ = newSyntaxTreeNode("relop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | GTE {$$ = newSyntaxTreeNode("relop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | EQ {$$ = newSyntaxTreeNode("relop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | NEQ {$$ = newSyntaxTreeNode("relop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; additive_expression : additive_expression addop term {$$ = newSyntaxTreeNode("additive-expression");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | term {$$ = newSyntaxTreeNode("additive-expression");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; addop : ADD {$$ = newSyntaxTreeNode("addop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | SUB {$$ = newSyntaxTreeNode("addop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; term : term mulop factor {$$ = newSyntaxTreeNode("term");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | factor {$$ = newSyntaxTreeNode("term");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; mulop : MUL {$$ = newSyntaxTreeNode("mulop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | DIV {$$ = newSyntaxTreeNode("mulop");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; factor : LPARENTHESE expression RPARENTHESE {$$ = newSyntaxTreeNode("factor");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | var {$$ = newSyntaxTreeNode("factor");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | call {$$ = newSyntaxTreeNode("factor");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | NUMBER {$$ = newSyntaxTreeNode("factor");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; call : ID LPARENTHESE args RPARENTHESE {$$ = newSyntaxTreeNode("call");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);SyntaxTreeNode_AddChild($$, $4);callback(1, $$);} ; args : arg_list {$$ = newSyntaxTreeNode("args");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} | epsilon {$$ = newSyntaxTreeNode("args");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; arg_list : arg_list COMMA expression {$$ = newSyntaxTreeNode("arg-list");SyntaxTreeNode_AddChild($$, $1);SyntaxTreeNode_AddChild($$, $2);SyntaxTreeNode_AddChild($$, $3);callback(1, $$);} | expression {$$ = newSyntaxTreeNode("arg-list");SyntaxTreeNode_AddChild($$, $1);callback(1, $$);} ; epsilon : {$$ = newSyntaxTreeNode("epsilon");callback(1, $$);} ; %% void yyerror(const char * s) { fprintf(stderr, "%s:%d syntax error for %s\n", s, pmyloc->first_line, yytext); } /// \brief Syntax analysis from input file to output file /// /// \param input basename of input file /// \param output basename of output file void syntax(const char * input, const char * output) { gt = newSyntaxTree(); char inputpath[256] = "./testcase/"; char outputpath[256] = "./syntree/"; strcat(inputpath, input); strcat(outputpath, output); if (!(yyin = fopen(inputpath, "r"))) { fprintf(stderr, "[ERR] Open input file %s failed.", inputpath); exit(1); } yyrestart(yyin); printf("[START]: Syntax analysis start for %s\n", input); FILE * fp = fopen(outputpath, "w+"); if (!fp) return; // reinitialize position counter pmyloc->first_line = pmyloc->first_column = pmyloc->last_line = pmyloc->last_column = 1; #ifdef TREE_GEN_GRAPH callback(0, output); #endif // yyerror() is invoked when yyparse fail. If you still want to check the return value, it's OK. // `while (!feof(yyin))` is not needed here. We only analyze once. // // If error occurs when parsing, nothing will be printed into output file, but tree data will still // availiable in stdout or tree file if ( yyparse() != 0 ) { printf("[ERR] Error parsing %s. Abort. \n", input); } else { printf("[OUTPUT] Printing tree to output file %s\n", outputpath); printSyntaxTree(fp, gt); deleteSyntaxTree(gt); gt = 0; printf("[END] Syntax analysis end for %s\n", input); } #ifdef TREE_GEN_GRAPH callback(-1, NULL); #endif fclose(fp); } /// \brief starting function for testing syntax module. /// /// Invoked in test_syntax.c int syntax_main(int argc, char ** argv) { /*#ifdef YYDEBUG*/ /*extern int yydebug;*/ /*yydebug = 1;*/ /*#endif*/ char filename[50][256]; char output_file_name[256]; char suffix[] = ".syntax_tree"; char extension[] = ".cminus"; int fn = getAllTestcase(filename); for (int i = 0; i < fn; i++) { strcpy(output_file_name, filename[i]); strcpy(output_file_name + strlen(output_file_name) - strlen(extension), suffix); syntax(filename[i], output_file_name); } return 0; }