%{
/*
* 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
*/