/* Copyright 2021 xensik. All rights reserved. // // Use of this source code is governed by a GNU GPLv3 license // that can be found in the LICENSE file. */ %option outfile="lexer.cpp" %option header-file="lexer.hpp" %option prefix="s1_" %option reentrant %option noyywrap batch nounput noinput %option never-interactive %option nounistd %top{ #include "stdafx.hpp" #include "s1.hpp" #include "parser.hpp" using namespace xsk::gsc; void s1_push_header(xsk::gsc::context* ctx, const std::string& file); void s1_pop_header(xsk::gsc::context* ctx); } %{ #define YY_USER_ACTION ctx->loc.columns(yyleng); %} RGX_PATH ([_A-Za-z0-9]+\\)+[_A-Za-z0-9]+ RGX_IDENTIFIER [_A-Za-z][_A-Za-z0-9]* RGX_STRING \"(?:\\.|[^\"])*?\"|\'(?:\\.|[^\'])*?\' RGX_COLOR #([0-9a-fA-F]{6}|[0-9a-fA-F]{3}) RGX_FLT_DEC [0-9]+\.(?:[0-9]*)?f?|\.[0-9]+f? RGX_INT_OCT 0[1-7][0-7]* RGX_INT_BIN 0[bB][01]+ RGX_INT_HEX 0[xX][0-9a-fA-F]+ RGX_INT_DEC [0-9]+ RGX_DEFAULT (.|\n) %x COMMENT_STATE %x DEV_OFF_STATE %s DEV_ON_STATE %% %{ ctx->loc.step(); %} [ \t\r] { ctx->loc.step(); } \n { ctx->loc.lines(yyleng); ctx->loc.step(); } "//".* "/*" { BEGIN(COMMENT_STATE); } . \n { ctx->loc.lines(yyleng); ctx->loc.step(); } "*/" { BEGIN(INITIAL); } <> { throw s1::parser::syntax_error(ctx->loc, "unmatched multiline comment start ('/*')"); } "*/" { throw s1::parser::syntax_error(ctx->loc, "unmatched multiline comment end ('*/')"); } "/#" { throw s1::parser::syntax_error(ctx->loc, "cannot recurse devblock ('/#')"); } "#/" { BEGIN(INITIAL); return s1::parser::make_DEVEND(ctx->loc); } <> { throw s1::parser::syntax_error(ctx->loc, "unmatched devblock start ('/#')"); } "/#" { BEGIN(ctx->mode == xsk::gsc::build::dev ? DEV_ON_STATE : DEV_OFF_STATE); if(ctx->mode == xsk::gsc::build::dev) return s1::parser::make_DEVBEGIN(ctx->loc); } . \n { ctx->loc.lines(yyleng); ctx->loc.step(); } "#/" { BEGIN(INITIAL); } <> { throw s1::parser::syntax_error(ctx->loc, "unmatched devblock start ('/#')"); } "#/" { throw s1::parser::syntax_error(ctx->loc, "unmatched devblock end ('#/')"); } "#inline" { return s1::parser::make_INLINE(ctx->loc); } "#include" { return s1::parser::make_INCLUDE(ctx->loc); } "#using_animtree" { return s1::parser::make_USINGTREE(ctx->loc); } "#animtree" { return s1::parser::make_ANIMTREE(ctx->loc); } "endon" { return s1::parser::make_ENDON(ctx->loc); } "notify" { return s1::parser::make_NOTIFY(ctx->loc); } "wait" { return s1::parser::make_WAIT(ctx->loc); } "waittill" { return s1::parser::make_WAITTILL(ctx->loc); } "waittillmatch" { return s1::parser::make_WAITTILLMATCH(ctx->loc); } "waittillframeend" { return s1::parser::make_WAITTILLFRAMEEND(ctx->loc); } "waitframe" { return s1::parser::make_WAITFRAME(ctx->loc); } "if" { return s1::parser::make_IF(ctx->loc); } "else" { return s1::parser::make_ELSE(ctx->loc); } "do" { return s1::parser::make_DO(ctx->loc); } "while" { return s1::parser::make_WHILE(ctx->loc); } "for" { return s1::parser::make_FOR(ctx->loc); } "foreach" { return s1::parser::make_FOREACH(ctx->loc); } "in" { return s1::parser::make_IN(ctx->loc); } "switch" { return s1::parser::make_SWITCH(ctx->loc); } "case" { return s1::parser::make_CASE(ctx->loc); } "default" { return s1::parser::make_DEFAULT(ctx->loc); } "break" { return s1::parser::make_BREAK(ctx->loc); } "continue" { return s1::parser::make_CONTINUE(ctx->loc); } "return" { return s1::parser::make_RETURN(ctx->loc); } "breakpoint" { return s1::parser::make_BREAKPOINT(ctx->loc); } "prof_begin" { return s1::parser::make_PROFBEGIN(ctx->loc); } "prof_end" { return s1::parser::make_PROFEND(ctx->loc); } "thread" { return s1::parser::make_THREAD(ctx->loc); } "childthread" { return s1::parser::make_CHILDTHREAD(ctx->loc); } "thisthread" { return s1::parser::make_THISTHREAD(ctx->loc); } "call" { return s1::parser::make_CALL(ctx->loc); } "true" { return s1::parser::make_TRUE(ctx->loc); } "false" { return s1::parser::make_FALSE(ctx->loc); } "undefined" { return s1::parser::make_UNDEFINED(ctx->loc); } ".size" { return s1::parser::make_SIZE(ctx->loc); } "game" { return s1::parser::make_GAME(ctx->loc); } "self" { return s1::parser::make_SELF(ctx->loc); } "anim" { return s1::parser::make_ANIM(ctx->loc); } "level" { return s1::parser::make_LEVEL(ctx->loc); } \( { return s1::parser::make_LPAREN(ctx->loc); } \) { return s1::parser::make_RPAREN(ctx->loc); } \{ { return s1::parser::make_LBRACE(ctx->loc); } \} { return s1::parser::make_RBRACE(ctx->loc); } \[ { return s1::parser::make_LBRACKET(ctx->loc); } \] { return s1::parser::make_RBRACKET(ctx->loc); } \, { return s1::parser::make_COMMA(ctx->loc); } \. { return s1::parser::make_DOT(ctx->loc); } \:\: { return s1::parser::make_DOUBLECOLON(ctx->loc); } \: { return s1::parser::make_COLON(ctx->loc); } \; { return s1::parser::make_SEMICOLON(ctx->loc); } \? { return s1::parser::make_QMARK(ctx->loc); } \+\+ { return s1::parser::make_INCREMENT(ctx->loc); } \-\- { return s1::parser::make_DECREMENT(ctx->loc); } \<\<\= { return s1::parser::make_ASSIGN_LSHIFT(ctx->loc); } \>\>\= { return s1::parser::make_ASSIGN_RSHIFT(ctx->loc); } \<\< { return s1::parser::make_LSHIFT(ctx->loc); } \>\> { return s1::parser::make_RSHIFT(ctx->loc); } \|\| { return s1::parser::make_OR(ctx->loc); } \&\& { return s1::parser::make_AND(ctx->loc); } \=\= { return s1::parser::make_EQUALITY(ctx->loc); } \!\= { return s1::parser::make_INEQUALITY(ctx->loc); } \<\= { return s1::parser::make_LESS_EQUAL(ctx->loc); } \>\= { return s1::parser::make_GREATER_EQUAL(ctx->loc); } \< { return s1::parser::make_LESS(ctx->loc); } \> { return s1::parser::make_GREATER(ctx->loc); } \+\= { return s1::parser::make_ASSIGN_ADD(ctx->loc); } \-\= { return s1::parser::make_ASSIGN_SUB(ctx->loc); } \*\= { return s1::parser::make_ASSIGN_MUL(ctx->loc); } \/\= { return s1::parser::make_ASSIGN_DIV(ctx->loc); } \%\= { return s1::parser::make_ASSIGN_MOD(ctx->loc); } \|\= { return s1::parser::make_ASSIGN_BW_OR(ctx->loc); } \&\= { return s1::parser::make_ASSIGN_BW_AND(ctx->loc); } \^\= { return s1::parser::make_ASSIGN_BW_EXOR(ctx->loc); } \= { return s1::parser::make_ASSIGN(ctx->loc); } \+ { return s1::parser::make_ADD(ctx->loc); } \- { return s1::parser::make_SUB(ctx->loc); } \* { return s1::parser::make_MUL(ctx->loc); } \/ { return s1::parser::make_DIV(ctx->loc); } \% { return s1::parser::make_MOD(ctx->loc); } \! { return s1::parser::make_NOT(ctx->loc); } \~ { return s1::parser::make_COMPLEMENT(ctx->loc); } \| { return s1::parser::make_BITWISE_OR(ctx->loc); } \& { return s1::parser::make_BITWISE_AND(ctx->loc); } \^ { return s1::parser::make_BITWISE_EXOR(ctx->loc); } {RGX_PATH} { return s1::parser::make_PATH(xsk::utils::string::fordslash(yytext), ctx->loc); } {RGX_IDENTIFIER} { return s1::parser::make_IDENTIFIER((std::string(yytext, 3) == "_ID") ? std::string(yytext) : xsk::utils::string::to_lower(yytext), ctx->loc); } \&{RGX_STRING} { return s1::parser::make_ISTRING(std::string(yytext).substr(1), ctx->loc); } {RGX_STRING} { return s1::parser::make_STRING(std::string(yytext), ctx->loc); } {RGX_COLOR} { return s1::parser::make_COLOR(std::string(yytext).substr(1), ctx->loc); } {RGX_FLT_DEC} { return s1::parser::make_FLOAT(std::string(yytext), ctx->loc); } {RGX_INT_OCT} { return s1::parser::make_INT_OCT(xsk::utils::string::oct_to_dec(yytext), ctx->loc); } {RGX_INT_BIN} { return s1::parser::make_INT_BIN(xsk::utils::string::bin_to_dec(yytext), ctx->loc); } {RGX_INT_HEX} { return s1::parser::make_INT_HEX(xsk::utils::string::hex_to_dec(yytext), ctx->loc); } {RGX_INT_DEC} { return s1::parser::make_INT_DEC(std::string(yytext), ctx->loc); } <> { if(ctx->header_top > 0) s1_pop_header(ctx); else return s1::parser::make_S1EOF(ctx->loc); } <*>{RGX_DEFAULT} { throw s1::parser::syntax_error(ctx->loc, "bad token: \'" + std::string(yytext) + "\'"); } %% void s1_push_header(xsk::gsc::context* ctx, const std::string& file) { try { if (ctx->header_top >= 4) { throw xsk::gsc::error("maximum gsh depth exceeded '4'"); } ctx->header_top++; char* buf_data = 0; size_t buf_size = 0; for (auto& src : *ctx->sources) { if (src.name == file) { buf_data = reinterpret_cast(src.buf.data()); buf_size = src.buf.size(); ctx->locs.push(ctx->loc); ctx->loc.initialize(&src.name); } } if (buf_data == 0) { ctx->sources->push_back(xsk::gsc::source()); auto& source = ctx->sources->back(); source.name = file; source.buf = ctx->read_callback(file + ".gsh"); source.buf.push_back(0); source.buf.push_back(0); buf_data = reinterpret_cast(source.buf.data()); buf_size = source.buf.size(); ctx->locs.push(ctx->loc); ctx->loc.initialize(&source.name); } auto state = new yy_buffer_state(); state->yy_buf_size = buf_size - 2; state->yy_buf_pos = state->yy_ch_buf = buf_data; state->yy_is_our_buffer = 0; state->yy_input_file = NULL; state->yy_n_chars = state->yy_buf_size; state->yy_is_interactive = 0; state->yy_at_bol = 1; state->yy_fill_buffer = 0; state->yy_buffer_status = 0; yypush_buffer_state(state, ctx->scanner); } catch (const std::exception& e) { throw xsk::gsc::error("parsing header file '" + file + "': " + e.what()); } } void s1_pop_header(xsk::gsc::context* ctx) { ctx->header_top--; ctx->loc = ctx->locs.top(); ctx->locs.pop(); yypop_buffer_state(ctx->scanner); }