parser.yy 5.6 KB
Newer Older
Genki Sakanashi's avatar
Genki Sakanashi committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
%skeleton "lalr1.cc"
%require "3.0"
%defines
%define api.value.type variant
%define api.token.constructor
%code requires {
  #include "Program.h"
  #include "Radix.h"
  #include "Variable.h"
}
%code{
  #include <string>
  #define YY_DECL yy::parser::symbol_type yylex()
  YY_DECL;
  extern int yylineno;


  void throw_syntax_error(std::string msg){
    throw yy::parser::syntax_error(msg);
  }

  Program p;
  Radix r;
}
%token VAR FLAG OPR ROT SET RESET OUTPUT INPUT END IF ELSE REPEAT BREAK SWITCH CASE0 CASE1 CASE2 EQ COLON INF GOTO IND_OPR CALL RETURN DEF PROTO FLIP AT
//%token D_NUMBER T_NUMBER ON OFF NAME T_TRUE T_FALSE
/*
%type <CodeBlock*> block
%type <int> on_off
%type <int> bool_const
%type <char*> num
*/
%type <CodeBlock*> block
%type <int> bool_const
%type <int> repeat_number
%type <long long> number
%type <CodeBlock*> case0
%type <CodeBlock*> case1
%type <CodeBlock*> case2
%type <std::string> escaped_ident
%type <std::string> variable_str
%type <Variable*> variable
%type <std::string> flag

%token <std::string> D_NUMBER
%token <std::string> T_NUMBER
%token <std::string> IDENT
%token <int> TRUE
%token <int> FALSE
%token <std::string> CON0
%token <std::string> CON1
%token <std::string> CON2
%token <std::string> BASE
%token <std::string> RETURN_ADDR

%token END_OF_FILE 0 "end of file"
%%

program : global_var_flag_decl_list prototypes routines {p.generate();}
        ;
global_var_flag_decl_list : global_var_flag_decl_list global_var_flag_decl
        |
        ;
global_var_flag_decl : var_decl
        | FLAG escaped_ident EQ bool_const {p.add_flag($2, $4);}
        ;
prototypes : prototypes prototype
        |
        ;
prototype : PROTO IDENT {p.add_routine($2, true);}
        ;
routines: routines routine
        |
        ;
routine : DEF IDENT {p.add_routine($2, false);} var_decl_list block END {p.current_routine->end();}
        ;
var_decl_list : var_decl_list var_decl
        |
        ;
var_decl : VAR escaped_ident EQ number {p.current_routine->add_var($2, $4);}
        ;
bool_const : TRUE {$$=FLAG_ON;}
        | FALSE {$$=FLAG_OFF;}
        ;
number  : D_NUMBER {$$=r.to($1, 10);}
        | T_NUMBER {auto s = $1;s.erase(--s.end());$$ = r.to(s, 3);}
        ;
block   : {p.current_routine->add_block();} statements {$$ = p.current_routine->pop_block();}
        ;
statements : statements statement
        |
        ;
statement : opr_statement
        | rot_statement
        | output_statement
        | input_statement
        | set_statement
        | reset_statement
        | if_statement
        | repeat_statement
        | break_statement
        | switch_statement
        | ind_opr_statement
        | call_statement
        | return_statement
        | flip_statement
        ;

opr_statement : OPR variable {p.current_routine->current_block()->opr($2);}
        ;
rot_statement : ROT variable {p.current_routine->current_block()->rot($2);}
        ;
ind_opr_statement : IND_OPR variable {p.current_routine->current_block()->ind_opr($2);}
        ;
output_statement : OUTPUT {p.current_routine->current_block()->output();}
        ;
input_statement : INPUT {p.current_routine->current_block()->input();}
        ;
set_statement : SET flag {p.current_routine->current_block()->set($2);}
        ;
reset_statement : RESET flag {p.current_routine->current_block()->reset($2);}
        ;
if_statement : IF flag block ELSE block END {p.current_routine->current_block()->if_statement($2, $3, $5);}
        ;
repeat_statement : REPEAT {p.current_routine->num_of_repeat_nested++;} repeat_number block END {p.current_routine->current_block()->repeat($3, $4);p.current_routine->num_of_repeat_nested--;}
        ;
repeat_number : number {$$=$1;}
        | INF {$$=INF_EXPR;}
        ;
break_statement : BREAK {p.current_routine->current_block()->repeat_break(1);}
        | BREAK number {p.current_routine->current_block()->repeat_break($2);}
        ;
switch_statement : SWITCH variable case0 case1 case2 END {p.current_routine->current_block()->switch_statement($2, $3, $4 ,$5);}
        ;
case0   : CASE0 block {$$=$2;}
        | {p.current_routine->add_block();$$ = p.current_routine->pop_block();}
        ;
case1   : CASE1 block {$$=$2;}
        | {p.current_routine->add_block();$$ = p.current_routine->pop_block();}
        ;
case2   : CASE2 block {$$=$2;}
        | {p.current_routine->add_block();$$ = p.current_routine->pop_block();}
        ;
call_statement : CALL IDENT {p.current_routine->current_block()->call($2);}
        ;
return_statement : RETURN {p.current_routine->current_block()->func_return();}
        ;
flip_statement : FLIP flag {p.current_routine->current_block()->flip($2);}
        ;
flag    : escaped_ident {p.check_flag($1);$$ = $1;}
        ;
variable : variable_str {
          auto routine = p.current_routine;
          if(routine->variables.count($1) == 0){
            if(p.global_routine->variables.count($1) == 0){
              throw_syntax_error("Undefined variable : '"+$1+"'");
            }else{
              routine = p.global_routine;
            }
          }
          $$ = routine->variables[$1];
        }
        | variable_str AT IDENT {
          if(p.routines.count($3) == 0){
            throw_syntax_error("Undefined routine : '"+$3+"'");
          }
          auto routine = p.routines[$3];
          if(routine->variables.count($1)){
            $$ = routine->variables[$1];
          }else{
            $$ = routine->add_var($1, 0);
            $$->is_defined = false;
          }
        }
variable_str : escaped_ident {$$=$1;}
        | CON0 {$$ = $1;}
        | CON1 {$$ = $1;}
        | CON2 {$$ = $1;}
        | BASE {$$ = $1;}
        | RETURN_ADDR {$$ = $1;}
        ;
escaped_ident : IDENT {$$ = "U_"+$1;}
        ;