%{ /* * Copyright (C) 1995-1997 Christopher D. Granz * * This header may not be removed. * * Refer to the file "License" included in this package for further * information and before using any of the following. */ #include <stdio.h> #include "emc.h" NODE *pTemp; %} %union { long lInt; double dFloat; intt iType; NODE *pNode; } %token <lInt> INT_CONSTANT %token <dFloat> FLOAT_CONSTANT %token STRING_LITERAL IDENTIFIER %token INFO GLOBAL %token RETURNED %token INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP %token MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN SUB_ASSIGN %token LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN %token INT FLOAT STRING OBJECT ARRAY %token IF ELSE DO WHILE FOR BROKEN CONTINUED %token BREAK CONTINUE RETURN %nonassoc LELSE %nonassoc ELSE %nonassoc LBROKEN %nonassoc BROKEN %nonassoc LCONTINUED %nonassoc CONTINUED %type <iType> type_specifier unary_operator assignment_operator %type <pNode> top_level global_statement function parameter_list opt_parameter_list parameter_declaration identifier primary_expr postfix_expr unary_expr multiplicative_expr additive_expr shift_expr relational_expr equality_expr and_expr exclusive_or_expr inclusive_or_expr logical_and_expr logical_or_expr conditional_expr assignment_expr expr_list opt_expr_list expr opt_expr declaration returned_list returned init_declarator_list init_declarator initializer_list initializer type_specifier_list declarator_list declarator statement_list statement compound_statement expression_statement if_statement loop_statement jump_statement %start top_level %% top_level : /* empty */ { $$ = pNodeTree = NULL; } | function { $$ = pNodeTree = $1; } ; global_statement : INFO STRING_LITERAL { pTemp = node_string( NODE_INFO, yytext ); } ';' { $$ = pTemp; } | GLOBAL type_specifier declarator_list ';' { $$ = node_tree( $2, NULL, $3 ); } ; function : identifier '(' opt_parameter_list ')' compound_statement { $$ = node_tree( NODE_FUNCTION, $1, node_tree( NODE_TREE, NULL, node_tree( NODE_TREE, $3, $5 ) ) ); } | type_specifier_list identifier '(' opt_parameter_list ')' compound_statement { $$ = node_tree( NODE_FUNCTION, $2, node_tree( NODE_TREE, $1, node_tree( NODE_TREE, $4, $6 ) ) ); } ; parameter_list : parameter_declaration { $$ = $1; } | parameter_list ',' parameter_declaration { $$ = node_tree( NODE_TREE, $1, $3 ); } ; opt_parameter_list : /* empty */ { $$ = NULL; } | parameter_list { $$ = $1; } ; parameter_declaration : type_specifier declarator { $$ = node_tree( $1, NULL, $2 ); } ; identifier : IDENTIFIER { $$ = node_string( NODE_IDENTIFIER, yytext ); } ; primary_expr : identifier { $$ = $1; } | INT_CONSTANT { $$ = node_int( $1 ); } | FLOAT_CONSTANT { $$ = node_float( $1 ); } | STRING_LITERAL { $$ = node_string( NODE_STRING, yytext ); } | '(' expr ')' { $$ = $2; } ; postfix_expr : primary_expr { $$ = $1; } | postfix_expr '[' expr ']' { $$ = node_tree( NODE_OPER_INDEX, $1, $3 ); } | postfix_expr '(' opt_expr_list ')' { $$ = node_tree( NODE_OPER_FUNC_CALL, $1, $3 ); } | postfix_expr INC_OP { $$ = node_tree( NODE_OPER_INC, $1, NULL ); } | postfix_expr DEC_OP { $$ = node_tree( NODE_OPER_DEC, $1, NULL ); } ; unary_expr : postfix_expr { $$ = $1; } | INC_OP unary_expr { $$ = node_tree( NODE_UOPER_INC, NULL, $2 ); } | DEC_OP unary_expr { $$ = node_tree( NODE_UOPER_DEC, NULL, $2 ); } | unary_operator unary_expr { $$ = node_tree( $1, NULL, $2 ); } ; unary_operator : '&' { $$ = NODE_UOPER_ADDRESS_OF; } | '@' { $$ = NODE_UOPER_BUILTIN_FUNC; } | '+' { $$ = NODE_UOPER_PLUS; } | '-' { $$ = NODE_UOPER_MINUS; } | '~' { $$ = 0; } | '!' { $$ = NODE_UOPER_NOT_EQUAL; } ; multiplicative_expr : unary_expr { $$ = $1; } | multiplicative_expr '*' unary_expr { $$ = node_tree( NODE_OPER_MUL, $1, $3 ); } | multiplicative_expr '/' unary_expr { $$ = node_tree( NODE_OPER_DIV, $1, $3 ); } | multiplicative_expr '%' unary_expr { $$ = node_tree( NODE_OPER_MOD, $1, $3 ); } ; additive_expr : multiplicative_expr { $$ = $1; } | additive_expr '+' multiplicative_expr { $$ = node_tree( NODE_OPER_ADD, $1, $3 ); } | additive_expr '-' multiplicative_expr { $$ = node_tree( NODE_OPER_SUB, $1, $3 ); } ; shift_expr : additive_expr { $$ = $1; } | shift_expr LEFT_OP additive_expr { $$ = node_tree( NODE_OPER_LEFT, $1, $3 ); } | shift_expr RIGHT_OP additive_expr { $$ = node_tree( NODE_OPER_RIGHT, $1, $3 ); } ; relational_expr : shift_expr { $$ = $1; } | relational_expr '<' shift_expr { $$ = node_tree( NODE_ROPER_LESS, $1, $3 ); } | relational_expr '>' shift_expr { $$ = node_tree( NODE_ROPER_GREATER, $1, $3 ); } | relational_expr LE_OP shift_expr { $$ = node_tree( NODE_ROPER_LESS_EQUAL, $1, $3 ); } | relational_expr GE_OP shift_expr { $$ = node_tree( NODE_ROPER_GREATER_EQUAL, $1, $3 ); } ; equality_expr : relational_expr { $$ = $1; } | equality_expr EQ_OP relational_expr { $$ = node_tree( NODE_ROPER_EQUAL, $1, $3 ); } | equality_expr NE_OP relational_expr { $$ = node_tree( NODE_ROPER_NOT_EQUAL, $1, $3 ); } ; and_expr : equality_expr { $$ = $1; } | and_expr '&' equality_expr { $$ = node_tree( NODE_OPER_AND, $1, $3 ); } ; exclusive_or_expr : and_expr { $$ = $1; } | exclusive_or_expr '^' and_expr { $$ = node_tree( NODE_OPER_XOR, $1, $3 ); } ; inclusive_or_expr : exclusive_or_expr { $$ = $1; } | inclusive_or_expr '|' exclusive_or_expr { $$ = node_tree( NODE_OPER_OR, $1, $3 ); } ; logical_and_expr : inclusive_or_expr { $$ = $1; } | logical_and_expr AND_OP inclusive_or_expr { $$ = node_tree( NODE_LOPER_AND, $1, $3 ); } ; logical_or_expr : logical_and_expr { $$ = $1; } | logical_or_expr OR_OP logical_and_expr { $$ = node_tree( NODE_LOPER_OR, $1, $3 ); } ; conditional_expr : logical_or_expr { $$ = $1; } | logical_or_expr '?' logical_or_expr ':' conditional_expr { $$ = node_tree( NODE_COPER_QUEST, $1, node_tree( NODE_COPER_COLON, $3, $5 ) ); } ; assignment_expr : conditional_expr { $$ = $1; } | postfix_expr assignment_operator assignment_expr { $$ = node_tree( $2, $1, $3 ); } ; assignment_operator : '=' { $$ = NODE_OPER_ASSIGN; } | MUL_ASSIGN { $$ = NODE_OPER_MUL_ASSIGN; } | DIV_ASSIGN { $$ = NODE_OPER_DIV_ASSIGN; } | MOD_ASSIGN { $$ = NODE_OPER_MOD_ASSIGN; } | ADD_ASSIGN { $$ = NODE_OPER_ADD_ASSIGN; } | SUB_ASSIGN { $$ = NODE_OPER_SUB_ASSIGN; } | LEFT_ASSIGN { $$ = NODE_OPER_LEFT_ASSIGN; } | RIGHT_ASSIGN { $$ = NODE_OPER_RIGHT_ASSIGN; } | AND_ASSIGN { $$ = NODE_OPER_AND_ASSIGN; } | XOR_ASSIGN { $$ = NODE_OPER_XOR_ASSIGN; } | OR_ASSIGN { $$ = NODE_OPER_OR_ASSIGN; } ; expr_list : expr { $$ = $1; } | expr_list ',' expr { $$ = node_tree( NODE_TREE, $1, $3 ); } ; opt_expr_list : /* empty */ { $$ = NULL; } | expr_list { $$ = $1; } ; expr : assignment_expr { $$ = $1; } ; opt_expr : /* empty */ { $$ = NULL; } | expr { $$ = $1; } ; declaration : RETURNED '{' returned_list '}' '=' postfix_expr ';' { $$ = node_tree( NODE_RETURNED, $3, $6 ); } | type_specifier init_declarator_list ';' { $$ = node_tree( $1, NULL, $2 ); } ; returned_list : returned { $$ = $1; } | returned_list ',' returned { $$ = node_tree( NODE_TREE, $1, $3 ); } ; returned : declarator { $$ = $1; } | type_specifier declarator { $$ = node_tree( $1, NULL, $2 ); } ; init_declarator_list : init_declarator { $$ = $1; } | init_declarator_list ',' init_declarator { $$ = node_tree( NODE_TREE, $1, $3 ); } ; init_declarator : declarator { $$ = $1; } | declarator '=' initializer { $$ = node_tree( NODE_OPER_ASSIGN, $1, $3 ); } ; initializer_list : initializer { $$ = $1; } | initializer_list ',' initializer { $$ = node_tree( NODE_TREE, $1, $3 ); } ; initializer : expr { $$ = $1; } | '{' initializer_list '}' { $$ = $2; } ; type_specifier_list : type_specifier { $$ = node_tree( $1, NULL, NULL ); } | type_specifier_list ',' type_specifier { $$ = node_tree( NODE_TREE, $1, node_tree( $3, NULL, NULL ) ); } ; type_specifier : INT { $$ = NODE_TYPE_INT; } | FLOAT { $$ = NODE_TYPE_FLOAT; } | STRING { $$ = NODE_TYPE_STRING; } | OBJECT { $$ = NODE_TYPE_OBJECT; } | ARRAY { $$ = NODE_TYPE_ARRAY; } ; declarator_list : declarator { $$ = $1; } | declarator_list ',' declarator { $$ = node_tree( NODE_TREE, $1, $3 ); } ; declarator : identifier { $$ = $1; } | '*' declarator { $$ = node_tree( NODE_STAR, NULL, $2 ); } ; statement_list : statement { $$ = $1; } | statement_list statement { $$ = node_tree( NODE_TREE, $1, $2 ); } ; statement : declaration { $$ = $1; } | compound_statement { $$ = $1; } | expression_statement { $$ = $1; } | if_statement { $$ = $1; } | loop_statement { $$ = $1; } | jump_statement { $$ = $1; } ; compound_statement : '{' '}' { $$ = NULL; } | '{' statement_list '}' { $$ = $2; } ; expression_statement : opt_expr_list ';' { $$ = $1; } ; if_statement : IF '(' expr ')' statement %prec LELSE { $$ = node_tree( NODE_IF, $3, $5 ); } | IF '(' expr ')' ELSE statement { $$ = node_tree( NODE_IF, $3, node_tree( NODE_ELSE, NULL, $6 ) ); } | IF '(' expr ')' statement ELSE statement { $$ = node_tree( NODE_IF, $3, node_tree( NODE_ELSE, $5, $7 ) ); } ; loop_statement : WHILE '(' opt_expr ')' statement { $$ = node_tree( NODE_WHILE, $3, $5 ); } | WHILE '(' opt_expr ')' statement BROKEN statement %prec LBROKEN { $$ = node_tree( NODE_WHILE, $3, node_tree( NODE_BROKEN, $5, $7 ) ); } | WHILE '(' opt_expr ')' statement CONTINUED statement %prec LCONTINUED { $$ = node_tree( NODE_WHILE, $3, node_tree( NODE_CONTINUED, $5, $7 ) ); } | WHILE '(' opt_expr ')' statement BROKEN statement CONTINUED statement { $$ = node_tree( NODE_WHILE, $3, node_tree( NODE_BROKEN, $5, node_tree( NODE_CONTINUED, $7, $9 ) ) ); } | WHILE '(' opt_expr ')' statement CONTINUED statement BROKEN statement { $$ = node_tree( NODE_WHILE, $3, node_tree( NODE_CONTINUED, $5, node_tree( NODE_BROKEN, $7, $9 ) ) ); } | DO statement WHILE '(' opt_expr ')' { $$ = node_tree( NODE_WHILE, $5, $2 ); } | DO statement WHILE '(' opt_expr ')' BROKEN statement %prec LBROKEN { $$ = node_tree( NODE_WHILE, $5, node_tree( NODE_BROKEN, $2, $8 ) ); } | DO statement WHILE '(' opt_expr ')' CONTINUED statement %prec LCONTINUED { $$ = node_tree( NODE_WHILE, $5, node_tree( NODE_CONTINUED, $2, $8 ) ); } | DO statement WHILE '(' opt_expr ')' BROKEN statement CONTINUED statement { $$ = node_tree( NODE_WHILE, $5, node_tree( NODE_BROKEN, $2, node_tree( NODE_CONTINUED, $8, $10 ) ) ); } | DO statement WHILE '(' opt_expr ')' CONTINUED statement BROKEN statement { $$ = node_tree( NODE_WHILE, $5, node_tree( NODE_CONTINUED, $2, node_tree( NODE_BROKEN, $8, $10 ) ) ); } | FOR '(' opt_expr_list ';' opt_expr_list ';' opt_expr_list ')' statement { $$ = NULL; } ; jump_statement : BREAK ';' { $$ = node_tree( NODE_BREAK, NULL, NULL ); } | CONTINUE ';' { $$ = node_tree( NODE_CONTINUE, NULL, NULL ); } | RETURN opt_expr ';' { $$ = node_tree( NODE_RETURN, $2, NULL ); } | RETURN '{' opt_expr_list '}' ';' { $$ = node_tree( NODE_RETURN, $3, NULL ); } ; %% extern char *yytext; extern int column; int yyerror( char *str ) { fflush( stderr ); fprintf( stderr, "\n%*s\n%*s\n", column, "^", column, str ); return ( 0 ); } /* * End of em.y */