%skeleton "lalr1.cc" %define "parser_class_name" "script_parser" %defines %{ #ifdef _MSC_VER #pragma warning(disable: 4800) #pragma warning(disable: 4267) #endif #include #include "node.h" class compiler; %} %parse-param { compiler& driver } %lex-param { compiler& driver } %locations %expect 1 /* if文で衝突が発生するので、1つの衝突は無視 */ %initial-action { // ロケーション初期化 @$.begin.filename = @$.end.filename = &driver.get_filename(); } ; // %debug %error-verbose // Symbols. %union { int ival; std::string *sval; int type; CValueList *value_list; CArgList *arglist; CDeclList *decls; CStateList *states; CStatement *statement; CArgDef *argdef; CArgs *args; CValueNode *value; CNode *expr; CAssign *assign; CStateBlock *block; } %{ #include "compiler.h" %} %token END_OF_FILE 0 "end of file" %token TK_IVAL "ival" %token TK_IDENTIFIER "identifier" %token TK_SVAL "sval" %token TK_LOGOR "||" %token TK_LOGAND "&&" %token TK_EQ "==" %token TK_NE "!=" %token TK_GE ">=" %token TK_LE "<=" %token TK_LSHIFT "<<" %token TK_RSHIFT ">>" %token TK_ADD_ASSIGN "+=" %token TK_SUB_ASSIGN "-=" %token TK_MUL_ASSIGN "*=" %token TK_DIV_ASSIGN "/=" %token TK_MOD_ASSIGN "%=" %token TK_IF "if" %token TK_ELSE "else" %token TK_WHILE "while" %token TK_FOR "for" %token TK_SWITCH "switch" %token TK_CASE "case" %token TK_DEFAULT "default" %token TK_BREAK "break" %token TK_RETURN "return" %token TK_INTEGER "int" %token TK_STRING "string" %token TK_VOID "void" %type expr %type value %type assign %type value_list %type arglist %type arg %type decls decl_list %type states state_list %type block %type args %type statement %type type %destructor { delete $$; } "identifier" %destructor { delete $$; } "sval" %destructor { delete $$; } value_list %destructor { delete $$; } arglist %destructor { delete $$; } arg %destructor { delete $$; } decls decl_list %destructor { delete $$; } states state_list %destructor { delete $$; } args %destructor { delete $$; } block %destructor { delete $$; } assign %destructor { delete $$; } statement %destructor { delete $$; } value %destructor { delete $$; } expr %left "||"; %left "&&"; %nonassoc "==" "!=" '>' '<' ">=" "<="; %left '&' '|'; %left "<<" ">>"; %left '+' '-'; %left '*' '/' '%'; %left NEG; %% %start unit; unit : define_or_state | unit define_or_state ; define_or_state : error ';' | function | declaration ; declaration : type value_list ';' { driver.DefineValue(@2, $1, $2); } | type "identifier" '(' ')' ';' { driver.DefineFunction(@2, $1, $2, NULL); } | type "identifier" '(' arglist ')' ';' { driver.DefineFunction(@2, $1, $2, $4); } | "void" "identifier" '(' ')' ';' { driver.DefineFunction(@2, TYPE_VOID, $2, NULL); } | "void" "identifier" '(' arglist ')' ';' { driver.DefineFunction(@2, TYPE_VOID, $2, $4); } ; value_list : value { $$ = new CValueList($1); } | value_list ',' value { $$ = $1->Add($3); } ; arglist : arg { $$ = new CArgList($1); } | arglist ',' arg { $$ = $1->Add($3); } ; arg : type { $$ = new CArgDef(@1, $1, NULL); } | type '&' { $$ = new CArgDef(@1, TypeToRef($1), NULL); } | type "identifier" { $$ = new CArgDef(@1, $1, $2); } | type '&' "identifier" { $$ = new CArgDef(@1, TypeToRef($1), $3); } | type "identifier" '[' ']' { $$ = new CArgDef(@1, TypeToRef($1), $2); } | type '&' "identifier" '[' ']' { $$ = new CArgDef(@1, TypeToRef($1), $3); } ; function : type "identifier" '(' ')' block { driver.AddFunction(@1, $1, $2, NULL, $5); } | type "identifier" '(' arglist ')' block { driver.AddFunction(@1, $1, $2, $4, $6); } | "void" "identifier" '(' ')' block { driver.AddFunction(@1, TYPE_VOID, $2, NULL, $5); } | "void" "identifier" '(' arglist ')' block { driver.AddFunction(@1, TYPE_VOID, $2, $4, $6); } ; type : "int" { $$ = TYPE_INTEGER; } | "string" { $$ = TYPE_STRING; } ; block : '{' decl_list state_list '}' { $$ = new CStateBlock($2, $3); } ; decl_list : { $$ = NULL } | decls { $$ = $1 } ; state_list : { $$ = NULL } | states { $$ = $1 } ; decls : type value_list ';' { $$ = new CDeclList(new CDecl($1, $2)); } | decls type value_list ';' { $$ = $1->Add(new CDecl($2, $3)); } ; states : statement { $$ = new CStateList($1); } | states statement { $$ = $1->Add($2); } ; statement : ';' { $$ = new CNopStatement(@1); } | assign ';' { $$ = new CAssignStatement(@1, $1); } | "identifier" '(' args ')' ';' { $$ = new CFunctionStatement(@1, $1, $3); } | "identifier" '(' ')' ';' { $$ = new CFunctionStatement(@1, $1, NULL); } | "case" expr ':' { $$ = new CCaseStatement(@1, $2); } | "default" ':' { $$ = new CDefaultStatement(@1); } | "break" ';' { $$ = new CBreakStatement(@1); } | "return" ';' { $$ = new CReturnStatement(@1, NULL); } | "return" expr ';' { $$ = new CReturnStatement(@1, $2); } | "if" '(' expr ')' statement { $$ = new CIfStatement(@1, $3, $5); } | "if" '(' expr ')' statement "else" statement { $$ = new CIfStatement(@1, $3, $5, $7); } | "for" '(' assign ';' expr ';' assign ')' statement { $$ = new CForStatement(@1, $3, $5, $7, $9); } | "while" '(' expr ')' statement { $$ = new CWhileStatement(@1, $3, $5); } | "switch" '(' expr ')' '{' state_list '}' { $$ = new CSwitchStatement(@1, $3, $6); } | block { $$ = new CBlockStatement(@1, $1); } ; assign : value '=' expr { $$ = new CAssign(@1, '=', $1, $3); } | value "+=" expr { $$ = new CAssign(@1, '+', $1, $3); } | value "-=" expr { $$ = new CAssign(@1, '-', $1, $3); } | value "*=" expr { $$ = new CAssign(@1, '*', $1, $3); } | value "/=" expr { $$ = new CAssign(@1, '/', $1, $3); } | value "%=" expr { $$ = new CAssign(@1, '%', $1, $3); } ; expr : expr "&&" expr { $$ = CNode::MakeNode(driver, @2, OP_LOGAND, $1, $3); } | expr "||" expr { $$ = CNode::MakeNode(driver, @2, OP_LOGOR, $1, $3); } | expr "==" expr { $$ = CNode::MakeNode(driver, @2, OP_EQ, $1, $3); } | expr "!=" expr { $$ = CNode::MakeNode(driver, @2, OP_NE, $1, $3); } | expr '>' expr { $$ = CNode::MakeNode(driver, @2, OP_GT, $1, $3); } | expr ">=" expr { $$ = CNode::MakeNode(driver, @2, OP_GE, $1, $3); } | expr '<' expr { $$ = CNode::MakeNode(driver, @2, OP_LT, $1, $3); } | expr "<=" expr { $$ = CNode::MakeNode(driver, @2, OP_LE, $1, $3); } | expr '&' expr { $$ = CNode::MakeNode(driver, @2, OP_AND, $1, $3); } | expr '|' expr { $$ = CNode::MakeNode(driver, @2, OP_OR, $1, $3); } | expr "<<" expr { $$ = CNode::MakeNode(driver, @2, OP_LSHIFT, $1, $3); } | expr ">>" expr { $$ = CNode::MakeNode(driver, @2, OP_RSHIFT, $1, $3); } | expr '-' expr { $$ = CNode::MakeNode(driver, @2, OP_MINUS, $1, $3); } | expr '+' expr { $$ = CNode::MakeNode(driver, @2, OP_PLUS, $1, $3); } | expr '*' expr { $$ = CNode::MakeNode(driver, @2, OP_TIMES, $1, $3); } | expr '/' expr { $$ = CNode::MakeNode(driver, @2, OP_DIVIDE, $1, $3); } | expr '%' expr { $$ = CNode::MakeNode(driver, @2, OP_MOD, $1, $3); } | '-' expr %prec NEG { $$ = CNode::MakeNode(driver, @2, OP_NEG, $2); } | '(' expr ')' { $$ = $2; } | value { $$ = $1; } | "ival" { $$ = new CNode(@1, OP_CONST, $1); } | "sval" { $$ = new CNode(@1, OP_STRING, $1); } | "identifier" '(' args ')' { $$ = new CFunctionNode(@1, $1, $3); } | "identifier" '(' ')' { $$ = new CFunctionNode(@1, $1, NULL); } ; value : "identifier" { $$ = new CValueNode(@1, $1); } | "identifier" '[' expr ']' { $$ = new CValueNode(@1, $1, $3); } ; args : expr { $$ = new CArgs($1); } | args ',' expr { $$ = $1->Add($3); } ; %% void yy::script_parser::error(const yy::script_parser::location_type& l, const std::string& m) { driver.error(l, m); }