/****************************************************/ /* File: tiny.y */ /* The TINY Yacc/Bison specification file */ /* Compiler Construction: Principles and Practice */ /* Kenneth C. Louden */ /****************************************************/ %{ #define YYPARSER /* distinguishes Yacc output from other code files */ #include "globals.h" #include "util.h" #include "scan.h" #include "parse.h" #define YYSTYPE TreeNode * static char * savedName; /* for use in assignments */ static int savedNumber; static int savedLineNo; /* ditto */ static TreeNode * savedTree; /* stores syntax tree for later return */ static int yylex(void); // added 11/2/11 to ensure no conflict with lex int yyerror(char * message); %} %token IF ELSE WHILE RETURN INT VOID %token EQ NE LT LE GT GE LPAREN RPAREN LBRACE LCURLY RBRACE RCURLY SEMI COMMA %token ID NUM %left PLUS MINUS %left TIMES OVER %right ASSIGN %nonassoc THEN %nonassoc ELSE %token ERROR %% /* Grammar for C-MINUS */ program : declaration_list {savedTree = $1;}; declaration_list : declaration_list declaration { YYSTYPE t = $1; if (t != NULL) { while (t->sibling != NULL) { t = t->sibling; } t->sibling = $2; $$ = $1; } else { $$ = $2; }; } | declaration { $$ = $1; } ; declaration : var_declaration {$$ = $1; } | func_declaration { $$ = $1; }; name_specifier : ID { savedName = copyString(tokenString); savedLineNo = lineno; }; number_specifier : NUM { savedNumber = atoi(tokenString); savedLineNo = lineno; }; var_declaration : type_specifier name_specifier SEMI { $$ = newDeclNode(VarK); $$->lineno = savedLineNo; $$->attr.name = savedName; $$->type = $1->type; free($1); } | type_specifier name_specifier LBRACE number_specifier RBRACE SEMI { $$ = newDeclNode(ArrVarK); $$->lineno = savedLineNo; if ($1->type == Integer) $$->type = IntegerArray; else $$->type = Void; $$->attr.name = savedName; free($1); $$->child[0] = newExpNode(ConstK); $$->child[0]->type = Integer; $$->child[0]->attr.val = savedNumber; }; type_specifier : INT { $$ = newTypeNode(TypeNameK); $$->type = Integer; } | VOID { $$ = newTypeNode(TypeNameK); $$->type = Void; }; func_declaration : type_specifier name_specifier { $$ = newDeclNode(FuncK); $$->lineno = savedLineNo; $$->attr.name = savedName; $$->type = $1->type; /* 타입 바로 복사 */ } LPAREN params RPAREN compound_stmt { $$ = $3; $$->child[0] = $5; /* params */ $$->child[1] = $7; /* compound_stmt */ }; params : param_list { $$ = $1; } | VOID { $$ = newDeclNode(NonArrParamK); $$->type = Void; }; param_list : param_list COMMA param { YYSTYPE t = $1; if (t != NULL) { while (t->sibling != NULL) { t = t->sibling; } t->sibling = $3; $$ = $1; } else { $$ = $3; }; } | param {$$ = $1; }; param : type_specifier name_specifier { $$ = newDeclNode(NonArrParamK); $$->attr.name = savedName; $$->type = $1->type; } | type_specifier name_specifier LBRACE RBRACE { $$ = newDeclNode(ArrParamK); $$->attr.name = savedName; if ($1->type == Integer) $$->type = IntegerArray; else $$->type = Void; }; compound_stmt : LCURLY local_declarations statement_list RCURLY { $$ = newStmtNode(CompK); $$->lineno = lineno; $$->child[0] = $2; $$->child[1] = $3; }; local_declarations : local_declarations var_declaration { YYSTYPE t = $1; if (t != NULL) { while (t->sibling != NULL) t = t->sibling; t->sibling = $2; $$ = $1; } else $$ = $2; } | { $$ = NULL; }; statement_list : statement_list statement { YYSTYPE t = $1; if (t != NULL) { while (t->sibling != NULL) t = t->sibling; t->sibling = $2; $$ = $1; } else $$ = $2; } | { $$ = NULL; }; statement : expression_stmt { $$ = $1; } | compound_stmt { $$ = $1; } | selection_stmt { $$ = $1; } | iteration_stmt { $$ = $1; } | return_stmt { $$ = $1; } ; expression_stmt : expression SEMI { $$ = $1; } | SEMI { $$ = NULL; } ; selection_stmt : IF LPAREN expression RPAREN statement %prec THEN { $$ = newStmtNode(IfK); $$->lineno = lineno; $$->child[0] = $3; $$->child[1] = $5; } | IF LPAREN expression RPAREN statement ELSE statement { $$ = newStmtNode(IfK); $$->lineno = lineno; $$->child[0] = $3; $$->child[1] = $5; $$->child[2] = $7; }; iteration_stmt : WHILE LPAREN expression RPAREN statement { $$ = newStmtNode(IterK); $$->lineno = lineno; $$->child[0] = $3; $$->child[1] = $5; }; return_stmt : RETURN SEMI { $$ = newStmtNode(ReturnK); $$->lineno = lineno; } | RETURN expression SEMI { $$ = newStmtNode(ReturnK); $$->lineno = lineno; $$->child[0] = $2; }; expression : var ASSIGN expression { $$ = newExpNode(AssignK); $$->lineno = lineno; $$->type = $3->type; $$->child[0] = $1; $$->child[1] = $3; } | simple_expression { $$ = $1; }; var : name_specifier { $$ = newExpNode(IdK); $$->attr.name = savedName; } | name_specifier { $$ = newExpNode(ArrIdK); $$->attr.name = savedName; } LBRACE expression RBRACE { $$ = $2; $$->child[0] = $4; }; simple_expression : additive_expression relop additive_expression { $$ = $2; $$->lineno = $2->lineno; $$->child[0] = $1; $$->child[1] = $3; $$->type = Integer; } | additive_expression { $$ = $1; }; relop : LE { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = LE; } | LT { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = LT; } | GT { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = GT; } | GE { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = GE; } | EQ { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = EQ; } | NE { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = NE; }; additive_expression : additive_expression addop term { $$ = $2; $$->lineno = $2->lineno; $$->child[0] = $1; $$->child[1] = $3; } | term { $$ = $1; }; addop : PLUS { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = PLUS; } | MINUS { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = MINUS; }; term : term mulop factor { $$ = $2; $$->lineno = $2->lineno; $$->child[0] = $1; $$->child[1] = $3; } | factor { $$ = $1; }; mulop : TIMES { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = TIMES; } | OVER { $$ = newExpNode(OpK); $$->lineno = lineno; $$->attr.op = OVER; }; factor : LPAREN expression RPAREN { $$ = $2; } | var { $$ = $1; } | call { $$ = $1; } | NUM { $$ = newExpNode(ConstK); $$->lineno = lineno; $$->type = Integer; $$->attr.val = atoi(tokenString); } ; call : name_specifier { $$ = newExpNode(CallK); $$->lineno = lineno; $$->attr.name = savedName; } LPAREN args RPAREN { $$ = $2; $$->child[0] = $4; }; args : arg_list { $$ = $1; } | { $$ = NULL; } ; arg_list : arg_list COMMA expression { YYSTYPE t = $1; if (t != NULL) { while (t->sibling != NULL) t = t->sibling; t->sibling = $3; $$ = $1; } else $$ = $3; } | expression { $$ = $1; } ; %% int yyerror(char * message) { fprintf(listing,"Syntax error at line %d: %s\n",lineno,message); fprintf(listing,"Current token: "); printToken(yychar,tokenString); Error = TRUE; return 0; } /* yylex calls getToken to make Yacc/Bison output * compatible with ealier versions of the TINY scanner */ static int yylex(void) { return getToken(); } TreeNode * parse(void) { yyparse(); return savedTree; }