%{ /* * =========================================================================== * Copyright (C) 2025 the OpenMoHAA team * * This file is part of OpenMoHAA source code. * * OpenMoHAA source code is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * OpenMoHAA source code is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenMoHAA source code; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * =========================================================================== * * * yyLexer.*: FLEX Lexical grammar for MoHScript. */ #include "scriptcompiler.h" #include "./yyParser.hpp" #include void fprintf2(FILE * f, const char *format, ...) { va_list va; static char buffer[4200]; va_start(va, format); vsprintf(buffer, format, va); va_end(va); gi.Printf(buffer); } #define fprintf fprintf2 const char *start_ptr; const char *in_ptr; extern int prev_yylex; extern int out_pos; extern int success_pos; parseStage_e parseStage; extern yyparsedata parsedata; void yyllocset(YYLTYPE * loc, uint32_t off) { success_pos = out_pos - yyleng + off; loc->sourcePos = success_pos; parsedata.pos = success_pos; } void yyreducepos(uint32_t off) { out_pos -= off; } #define YYLEX(n) \ { \ yyllocset(&yylloc, 0); \ prev_yylex = n; \ return n; \ } #define YYLEXOFF(n, off) \ { \ yyllocset(&yylloc, off); \ prev_yylex = n; \ return n; \ } #define YY_USER_ACTION \ { \ out_pos += yyleng - yy_more_len; \ yylloc.sourcePos = out_pos; \ parsedata.pos = out_pos; \ } #define YY_FATAL_ERROR(n) yylexerror(n) void yylexerror(const char *msg) { gi.DPrintf("%s\n%s", msg, yytext); assert(0); } static void TextEscapeValue(char *str, size_t len) { char *to = parsetree_malloc(len + 1); yylval.s.val.stringValue = to; while (len) { if (*str == '\\') { if (len == 1) { break; } if (str[1] == 'n') { *to = '\n'; to++; } else if (str[1] == 't') { *to = '\t'; to++; } else if (str[1] == '"') { *to = '\"'; to++; } else { *to = str[1]; to++; } len -= 2; str += 2; } else { *to = *str; to++; len--; str++; } } *to = 0; } static void TextValue(char *str, size_t len) { char *s = parsetree_malloc(len + 1); strncpy(s, str, len); s[len] = 0; yylval.s.val.stringValue = s; } static bool UseField(void) { return prev_yylex == TOKEN_PERIOD || prev_yylex == TOKEN_DOLLAR; } #define YY_INPUT(buf, result, max_size) \ { \ char c; \ int n; \ \ c = '*'; \ for (n = 0; n < max_size; n++) { \ c = *in_ptr++; \ if (!c || c == '\n') { \ break; \ } \ \ buf[n] = c; \ } \ \ if (c == '\n') { \ buf[n++] = c; \ } else if (!c) { \ in_ptr--; \ } \ \ result = n; \ } %} /*%option debug*/ %option warn nodefault %option never-interactive %option yylineno %x SCRIPT %x C_COMMENT %x C_LINE_COMMENT %x VARIABLES %x IDENTIFIER string ([^\\\"\r\n]|\\.)* identifier [^\{\}\(\)\[\]\r\n\,:; \t] nonexpr [0-9a-zA-Z_\"'?@#`\.\x80-\xff] nonnumeric [a-zA-Z_\"'?@#`\x80-\xff] alphanum [a-zA-Z0-9_]+ varname [a-zA-Z0-9_\"$\\]+ %% "/*" { BEGIN(C_COMMENT); } "*/" { BEGIN(INITIAL); } \n { ; } . { ; } "*/" { Compiler.CompileError( parsedata.pos - yyleng, "'*/' found outside of comment" ); } \\[\r\n]+ { ; } "//"[^\r\n]* { if(prev_yylex != TOKEN_EOL) YYLEX(TOKEN_EOL); } "size" { BEGIN(INITIAL); YYLEX(TOKEN_SIZE); } [ \t]*\./([0-9]*[^0-9[:space:]]) { YYLEX(TOKEN_PERIOD); } \"{string}\" { BEGIN(INITIAL); TextEscapeValue(yytext + 1, strlen( yytext ) - 2 ); YYLEX(TOKEN_STRING); } {varname} { TextEscapeValue(yytext, strlen(yytext)); YYLEX(TOKEN_IDENTIFIER); } [ \t\r\n] { BEGIN(INITIAL); unput(yytext[yyleng - 1]); yyreducepos(1); } . { BEGIN(INITIAL); unput(yytext[yyleng - 1]); yyreducepos(1); } \"{string}\"{nonexpr} { BEGIN(IDENTIFIER); yymore(); } \"{string}\" { TextEscapeValue(yytext + 1, yyleng - 2); YYLEX(TOKEN_STRING); } "?" { YYLEX(TOKEN_TERNARY); } "if" { YYLEX(TOKEN_IF); } "else" { YYLEX(TOKEN_ELSE); } "while" { YYLEX(TOKEN_WHILE); } "for" { YYLEX(TOKEN_FOR); } "do" { YYLEX(TOKEN_DO); } "game" { BEGIN(VARIABLES); yylval.s.val = node1_(method_game); YYLEX(TOKEN_LISTENER); } "group" { BEGIN(VARIABLES); yylval.s.val = node1_(method_group); YYLEX(TOKEN_LISTENER); } "level" { BEGIN(VARIABLES); yylval.s.val = node1_(method_level); YYLEX(TOKEN_LISTENER); } "local" { BEGIN(VARIABLES); yylval.s.val = node1_(method_local); YYLEX(TOKEN_LISTENER); } "parm" { BEGIN(VARIABLES); yylval.s.val = node1_(method_parm); YYLEX(TOKEN_LISTENER); } "owner" { BEGIN(VARIABLES); yylval.s.val = node1_(method_owner); YYLEX(TOKEN_LISTENER); } "self" { BEGIN(VARIABLES); yylval.s.val = node1_(method_self); YYLEX(TOKEN_LISTENER); } "{" { parsedata.braces_count++; YYLEX(TOKEN_LEFT_BRACES); } "}" { parsedata.braces_count--; YYLEX(TOKEN_RIGHT_BRACES); } "(" { YYLEX(TOKEN_LEFT_BRACKET); } ")" { BEGIN(VARIABLES); YYLEX(TOKEN_RIGHT_BRACKET); } "[" { YYLEX(TOKEN_LEFT_SQUARE_BRACKET); } "]" { BEGIN(VARIABLES); YYLEX(TOKEN_RIGHT_SQUARE_BRACKET); } "=" { YYLEX(TOKEN_ASSIGNMENT); } ":" { YYLEX(TOKEN_COLON); } "::" { YYLEX(TOKEN_DOUBLE_COLON); } ";" { YYLEX(TOKEN_SEMICOLON); } "==" { YYLEX(TOKEN_EQUALITY); } "ifequal" { YYLEX(TOKEN_EQUALITY); } "ifstrequal" { YYLEX(TOKEN_EQUALITY); } "||" { YYLEX(TOKEN_LOGICAL_OR); } "&&" { YYLEX(TOKEN_LOGICAL_AND); } "|" { YYLEX(TOKEN_BITWISE_OR); } "^" { YYLEX(TOKEN_BITWISE_EXCL_OR); } "&" { YYLEX(TOKEN_BITWISE_AND); } "!=" { YYLEX(TOKEN_INEQUALITY); } "ifnotequal" { YYLEX(TOKEN_INEQUALITY); } "ifstrnotequal" { YYLEX(TOKEN_INEQUALITY); } "<" { YYLEX(TOKEN_LESS_THAN); } "ifless" { YYLEX(TOKEN_LESS_THAN); } ">" { YYLEX(TOKEN_GREATER_THAN); } "ifgreater" { YYLEX(TOKEN_GREATER_THAN); } "<=" { YYLEX(TOKEN_LESS_THAN_OR_EQUAL); } "iflessequal" { YYLEX(TOKEN_LESS_THAN_OR_EQUAL); } ">=" { YYLEX(TOKEN_GREATER_THAN_OR_EQUAL); } "ifgreaterequal" { YYLEX(TOKEN_GREATER_THAN_OR_EQUAL); } [ \t]"-" { YYLEX(TOKEN_NEG); } "+" { YYLEX(TOKEN_PLUS); } "+=" { YYLEX(TOKEN_PLUS_EQUALS); } "++"|[ \t]"++" { YYLEX(TOKEN_INCREMENT); } "-"|"-"[ \t]|[ \t]"-"[ \t] { YYLEX(TOKEN_MINUS); } "-=" { YYLEX(TOKEN_MINUS_EQUALS); } [ \t]"-=" { YYLEX(TOKEN_MINUS_EQUALS); } "--"|[ \t]"--" { YYLEX(TOKEN_DECREMENT); } "*" { YYLEX(TOKEN_MULTIPLY); } "*=" { YYLEX(TOKEN_MULTIPLY_EQUALS); } "/" { YYLEX(TOKEN_DIVIDE); } "/=" { YYLEX(TOKEN_DIVIDE_EQUALS); } "%" { YYLEX(TOKEN_MODULUS); } "%=" { YYLEX(TOKEN_MODULUS_EQUALS); } "<<" { YYLEX(TOKEN_SHIFT_LEFT); } "<<=" { YYLEX(TOKEN_SHIFT_LEFT_EQUALS); } ">>" { YYLEX(TOKEN_SHIFT_RIGHT); } ">>=" { YYLEX(TOKEN_SHIFT_RIGHT_EQUALS); } "&=" { YYLEX(TOKEN_AND_EQUALS); } "^=" { YYLEX(TOKEN_EXCL_OR_EQUALS); } "|=" { YYLEX(TOKEN_OR_EQUALS); } [$]+ { BEGIN( VARIABLES ); YYLEX(TOKEN_DOLLAR); } "!" { YYLEX(TOKEN_NOT); } "~" { YYLEX(TOKEN_COMPLEMENT); } "." { YYLEX(TOKEN_PERIOD); } "," { YYLEX(TOKEN_COMMA); } "NULL" { YYLEX(TOKEN_NULL); } "NIL" { YYLEX(TOKEN_NIL); } "try" { YYLEX(TOKEN_TRY); } "catch" { YYLEX(TOKEN_CATCH); } "switch" { YYLEX(TOKEN_SWITCH); } "case" { YYLEX(TOKEN_CASE); } "break" { YYLEX(TOKEN_BREAK); } "continue" { YYLEX(TOKEN_CONTINUE); } "makearray"|"makeArray" { YYLEX(TOKEN_MAKEARRAY); } "endarray"|"endArray" { YYLEX(TOKEN_ENDARRAY); } [\r\n]+ { if (prev_yylex != TOKEN_EOL) YYLEX(TOKEN_EOL); } [ \t] { ; } [0-9]+ { char* p = nullptr; yylval.s.val.intValue = std::strtol(yytext, &p, 10); YYLEX(TOKEN_INTEGER); } [0-9\.]+{nonnumeric} { BEGIN(IDENTIFIER); yymore(); } [0-9\.]+|[0-9\.]+("e+"|"e-")+[0-9\.] { char* p = nullptr; yylval.s.val.floatValue = std::strtof(yytext, &p); YYLEX(TOKEN_FLOAT); } {identifier}* { BEGIN(INITIAL); TextEscapeValue(yytext, yyleng); YYLEX(TOKEN_IDENTIFIER); } [ \t\r\n] { BEGIN(INITIAL); unput(yytext[yyleng - 1]); yyreducepos(1); TextEscapeValue(yytext, yyleng - 1); YYLEXOFF(TOKEN_IDENTIFIER, 1); } . { BEGIN(INITIAL); unput(yytext[yyleng - 1]); yyreducepos(1); TextEscapeValue(yytext, yyleng - 1); YYLEXOFF(TOKEN_IDENTIFIER, 1); } {identifier} { BEGIN(IDENTIFIER); yymore(); } [a-zA-Z0-9_]+ { BEGIN(IDENTIFIER); yymore(); }