/
Sapphire/bin/
Sapphire/db/
Sapphire/db/OLC_rooms/
Sapphire/db/abi/
Sapphire/db/em_src/
Sapphire/db/helps/
Sapphire/db/helps/emman/ifunc/
Sapphire/db/npcs/Tatt/
Sapphire/db/objects/Tatt/
Sapphire/db/q_data/
Sapphire/db/rooms/Tatt/
Sapphire/doc/
Sapphire/doc/em/
Sapphire/etc/
Sapphire/src/abic/
Sapphire/src/areacon/
Sapphire/src/client/
Sapphire/src/embc/
Sapphire/src/emi/
Sapphire/src/emi/test/
Sapphire/src/include/
Sapphire/src/sapphire/em/
Sapphire/src/tcon/
%{

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