/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . * */ %option noyywrap %option noinput %option nounput %option never-interactive %option case-insensitive %option outfile="engines/director/lingo/lingo-lex.cpp" %{ #define YY_NO_UNISTD_H #define FORBIDDEN_SYMBOL_EXCEPTION_FILE #define FORBIDDEN_SYMBOL_EXCEPTION_fprintf #define FORBIDDEN_SYMBOL_EXCEPTION_fwrite #define FORBIDDEN_SYMBOL_EXCEPTION_fread #define FORBIDDEN_SYMBOL_EXCEPTION_stdin #define FORBIDDEN_SYMBOL_EXCEPTION_stdout #define FORBIDDEN_SYMBOL_EXCEPTION_stderr #define FORBIDDEN_SYMBOL_EXCEPTION_exit #define FORBIDDEN_SYMBOL_EXCEPTION_getc #include "common/str.h" #include "director/director.h" #include "director/lingo/lingo.h" #include "director/lingo/lingo-ast.h" #include "director/lingo/lingo-codegen.h" #include "director/lingo/lingo-gr.h" #include "director/lingo/lingo-the.h" using namespace Director; static const char *inputbuffer; static uint inputlen; // Push lines in stack static void pushLine(uint num) { LingoCompiler *compiler = g_lingo->_compiler; if (num > inputlen) return; compiler->_lines[2] = compiler->_lines[1]; compiler->_lines[1] = compiler->_lines[0]; compiler->_lines[0] = &inputbuffer[num]; } static void count() { LingoCompiler *compiler = g_lingo->_compiler; if (debugChannelSet(-1, kDebugParse)) debug("LEXER: Read '%s' at %d:%d", yytext, compiler->_linenumber, compiler->_colnumber); char *p = yytext; while (*p) { if (*p == '\n') { compiler->_linenumber++; compiler->_colnumber = 0; pushLine(compiler->_bytenumber + 1); } else if (*p == '\xC2' && *(p + 1) == '\xAC') { // continuation compiler->_linenumber++; compiler->_colnumber = 0; } else { compiler->_colnumber++; } p++; compiler->_bytenumber++; } } static Common::String *cleanupString(const char *s) { Common::String *res = new Common::String; while (*s) { if (*s == '\xC2' && *(s + 1) == '\xAC') { // continuation s += 2; *res += ' '; // replace with space continue; } *res += *s; s++; } return res; } static void skipWhitespace(const char **ptr) { while (true) { if (**ptr == ' ' || **ptr == '\t') { *ptr += 1; } else if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation *ptr += 2; } else { break; } } } static Common::String *readUntilWhitespace(const char **ptr) { Common::String *res = new Common::String; while (true) { if (**ptr == ' ' || **ptr == '\t') { break; } if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation break; } *res += **ptr; *ptr += 1; } return res; } static Common::String *readUntilNull(const char **ptr) { Common::String *res = new Common::String; while (**ptr) { if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation *ptr += 2; *res += ' '; // replace with space continue; } *res += **ptr; *ptr += 1; } return res; } %} identifier [_[:alpha:]][_\.[:alnum:]]* constfloat [[:digit:]]+\.[[:digit:]]* constinteger [[:digit:]]+ conststring \"[^\"\r\n]*\" operator [-+*/%^:,()><&\[\]] newline (" "|\t|\xC2\xAC)*[\n\r] spc (" "|\t|\xC2\xAC) eventname (keyDown|keyUp|mouseDown|mouseUp|timeOut) unparsedstmt [^\r\n]* %% {spc}+ { count(); } [#]{identifier} { count(); yylval.s = new Common::String(yytext + 1); return tSYMBOL; } // D3, skip '#' abbreviated { count(); return tABBREVIATED; } abbrev { count(); return tABBREV; } abbr { count(); return tABBR; } after { count(); return tAFTER; } // D3 and { count(); return tAND; } before { count(); return tBEFORE; } // D3 cast { count(); return tCAST; } castlib { count(); return tCASTLIB; } // D5 castlibs { count(); return tCASTLIBS; } // D5 char { count(); return tCHAR; } // D3 chars { count(); return tCHARS; } contains { count(); return tCONTAINS; } date { count(); return tDATE; } delete { count(); return tDELETE; } down { count(); return tDOWN; } else { count(); return tELSE; } end({spc}+{identifier})? { count(); const char *ptr = &yytext[3]; // Skip 'end ' skipWhitespace(&ptr); if (!scumm_stricmp(ptr, "if")) return tENDIF; else if (!scumm_stricmp(ptr, "repeat")) return tENDREPEAT; else if (!scumm_stricmp(ptr, "tell")) return tENDTELL; yylval.s = new Common::String(ptr); return tENDCLAUSE; } exit { count(); return tEXIT; } ^{spc}*factory { count(); return tFACTORY; } field { count(); return tFIELD; } frame { count(); return tFRAME; } global { count(); return tGLOBAL; } go({spc}+to)? { count(); return tGO; } hilite { count(); return tHILITE; } if { count(); return tIF; } instance { count(); return tINSTANCE; } intersects { count(); return tINTERSECTS;} into { count(); return tINTO; } in { count(); return tIN; } item { count(); return tITEM; } items { count(); return tITEMS; } last { count(); return tLAST; } line { count(); return tLINE; } lines { count(); return tLINES; } long { count(); return tLONG; } macro { count(); return tMACRO; } member { count(); return tMEMBER; } menu { count(); return tMENU; } menus { count(); return tMENUS; } menuItem { count(); return tMENUITEM;} menuItems { count(); return tMENUITEMS; } method { count(); return tMETHOD; } mod { count(); return tMOD;} movie { count(); return tMOVIE; } next { count(); return tNEXT; } not { count(); return tNOT; } number { count(); return tNUMBER; } of { count(); return tOF; } on { count(); return tON; } // D3 open { count(); return tOPEN; } or { count(); return tOR; } play { count(); return tPLAY; } previous { count(); return tPREVIOUS; } property { count(); return tPROPERTY; } // D4 put { count(); return tPUT; } repeat { count(); return tREPEAT; } return { count(); return tRETURN; } script { count(); return tSCRIPT; } scummvmAssertError { count(); return tASSERTERROR; } set { count(); return tSET; } short { count(); return tSHORT; } sound { count(); return tSOUND; } sprite { count(); return tSPRITE; } starts { count(); return tSTARTS; } tell { count(); return tTELL; } the { count(); return tTHE; } then { count(); return tTHEN; } time { count(); return tTIME; } to { count(); return tTO; } when{spc}+{eventname}{spc}+then{spc}+{unparsedstmt} { count(); const char *ptr = &yytext[5]; // Skip 'when ' skipWhitespace(&ptr); Common::String *eventName = readUntilWhitespace(&ptr); skipWhitespace(&ptr); ptr += 5; // Skip 'then ' skipWhitespace(&ptr); Common::String *stmt = readUntilNull(&ptr); yylval.w.eventName = eventName; yylval.w.stmt = stmt; return tWHEN; } while { count(); return tWHILE; } window { count(); return tWINDOW; } with { count(); return tWITH; } within { count(); return tWITHIN; } word { count(); return tWORD; } words { count(); return tWORDS; } xtras { count(); return tXTRAS; } // D5 [<][>] { count(); return tNEQ; } [>][=] { count(); return tGE; } [<][=] { count(); return tLE; } [&][&] { count(); return tCONCAT; } [=] { count(); return tEQ; } {identifier} { count(); yylval.s = new Common::String(yytext); return tVARID; } {constfloat} { count(); yylval.f = atof(yytext); return tFLOAT; } {constinteger} { count(); yylval.i = strtol(yytext, NULL, 10); return tINT; } {operator} { count(); return *yytext; } {newline} { count(); return '\n'; } {conststring} { count(); yylval.s = cleanupString(&yytext[1]); yylval.s->deleteLastChar(); return tSTRING; } . { count(); } %% extern int yydebug; namespace Director { int LingoCompiler::parse(const char *code) { inputbuffer = code; _bytenumber = 0; inputlen = strlen(code); _lines[0] = _lines[1] = _lines[2] = code; YY_BUFFER_STATE bp; if (debugChannelSet(-1, kDebugParse)) yydebug = 1; else yydebug = 0; yy_delete_buffer(YY_CURRENT_BUFFER); bp = yy_scan_string(code); yy_switch_to_buffer(bp); yyparse(); yy_delete_buffer(bp); return 0; } } // End of namespace Director