aboutsummaryrefslogtreecommitdiff
path: root/engines/director/lingo/lingo-lex.l
diff options
context:
space:
mode:
Diffstat (limited to 'engines/director/lingo/lingo-lex.l')
-rw-r--r--engines/director/lingo/lingo-lex.l243
1 files changed, 243 insertions, 0 deletions
diff --git a/engines/director/lingo/lingo-lex.l b/engines/director/lingo/lingo-lex.l
new file mode 100644
index 0000000000..c2a5b19fb9
--- /dev/null
+++ b/engines/director/lingo/lingo-lex.l
@@ -0,0 +1,243 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+%option noyywrap
+%{
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/str.h"
+
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-gr.h"
+
+using namespace Director;
+
+int yyparse();
+static void count() {
+ g_lingo->_colnumber += strlen(yytext);
+}
+
+#if defined(__PLAYSTATION2__) || defined(_MSC_VER)
+// Stub for missing function
+int isatty(int fileno) { return 0; }
+#endif
+
+#ifdef _MSC_VER
+#define YY_NO_UNISTD_H
+#endif
+
+static void countnl() {
+ char *p = yytext;
+
+ while(*p == '\n' || *p == '\r')
+ p++;
+
+ g_lingo->_linenumber++;
+ g_lingo->_colnumber = strlen(p);
+}
+
+%}
+
+identifier [_[:alpha:]][_[:alnum:]]*
+constfloat [[:digit:]]+\.[[:digit:]]*
+constinteger [[:digit:]]+
+conststring \"[^\"\r\n]*\"
+operator [-+*/%=^:,()><&]
+newline [ \t]*[\n\r]
+whitespace [\t ]
+
+%%
+
+--[^\r\n]*
+^{whitespace}+ { count(); }
+[\t]+ { count(); return ' '; }
+
+(?i:and) { count(); return tAND; }
+(?i:contains) { count(); return tCONTAINS; }
+(?i:done) { count(); return tDONE; }
+(?i:down) { count(); return tDOWN; }
+(?i:if) { count(); return tIF; }
+(?i:[\n\r]+[\t ]*else[\t ]+if) { countnl(); return tNLELSIF; }
+(?i:[\n\r]+[\t ]*else) { countnl(); return tNLELSE; }
+(?i:else) { count(); return tELSE; }
+(?i:end) { count(); return tEND; }
+(?i:factory) { count(); return tFACTORY; }
+(?i:exit) { count(); return tEXIT; }
+(?i:frame) { count(); return tFRAME; }
+(?i:global) { count(); return tGLOBAL; }
+(?i:go[\t ]+to) { count(); return tGO; }
+(?i:go) { count(); return tGO; }
+(?i:instance) { count(); return tINSTANCE; }
+(?i:intersects) { count(); return tINTERSECTS; }
+(?i:into) { count(); return tINTO; }
+(?i:loop) { count(); return tLOOP; }
+(?i:macro) { count(); return tMACRO; }
+(?i:method) { count(); return tMETHOD; }
+(?i:mod) { count(); return tMOD; }
+(?i:movie) { count(); return tMOVIE; }
+(?i:next) { count(); return tNEXT; }
+(?i:not) { count(); return tNOT; }
+(?i:of) { count(); return tOF; }
+(?i:open) { count(); return tOPEN; }
+(?i:or) { count(); return tOR; }
+(?i:play) { count(); return tPLAY; }
+(?i:previous) { count(); return tPREVIOUS; }
+(?i:put) { count(); return tPUT; }
+(?i:repeat) { count(); return tREPEAT; }
+(?i:set) { count(); return tSET; }
+(?i:starts) { count(); return tSTARTS; }
+(?i:the[ \t]+sqrt[\t ]+of[\t ]+) {
+ count();
+
+ yylval.e[0] = g_lingo->_theEntities["sqrt"]->entity;
+ yylval.e[1] = 0; // No field
+
+ return THEENTITYWITHID;
+ }
+(?i:the[ \t]+[[:alpha:]]+[\t ]+of[\t ]+[[:alpha:]]+) {
+ count();
+
+ const char *ptr = &yytext[4]; // Skip 'the '
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+
+ Common::String field;
+ while (*ptr != ' ' && *ptr != '\t')
+ field += *ptr++;
+
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+
+ ptr += 3; // Skip 'of '
+
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+
+ if (g_lingo->_theEntities.contains(ptr)) {
+ field = Common::String::format("%d%s", g_lingo->_theEntities[ptr]->entity, field.c_str());
+
+ if (!g_lingo->_theEntityFields.contains(field)) {
+ error("Unhandled the field %s", ptr);
+ }
+
+ if (g_lingo->_theEntityFields[field]->entity != g_lingo->_theEntities[ptr]->entity)
+ error("Unsupported field '%s' for entity '%s'", field.c_str(), ptr);
+
+ yylval.e[0] = g_lingo->_theEntities[ptr]->entity;
+ yylval.e[1] = g_lingo->_theEntityFields[field]->field;
+
+ if (g_lingo->_theEntities[ptr]->hasId)
+ return THEENTITYWITHID;
+ else
+ return THEENTITY;
+ }
+
+ warning("Unhandled the entity %s", ptr);
+ }
+(?i:the[ \t]+[[:alpha:]]+) {
+ count();
+
+ const char *ptr = &yytext[4]; // Skip 'the '
+ while (*ptr == ' ' || *ptr == '\t')
+ ptr++;
+
+ if (g_lingo->_theEntities.contains(ptr)) {
+ yylval.e[0] = g_lingo->_theEntities[ptr]->entity;
+ yylval.e[1] = 0; // No field
+
+ if (g_lingo->_theEntities[ptr]->hasId)
+ return THEENTITYWITHID;
+ else
+ return THEENTITY;
+ }
+
+ warning("Unhandled the entity %s", ptr);
+ }
+(?i:then) { count(); return tTHEN; }
+(?i:to) { count(); return tTO; }
+(?i:sprite) { count(); return tSPRITE; }
+(?i:with) { count(); return tWITH; }
+(?i:within) { count(); return tWITHIN; }
+(?i:when) { count(); return tWHEN; }
+(?i:while) { count(); return tWHILE; }
+
+[<][>] { count(); return tNEQ; }
+[>][=] { count(); return tGE; }
+[<][=] { count(); return tLE; }
+[&][&] { count(); return tCONCAT; }
+
+{identifier} {
+ count();
+ yylval.s = new Common::String(yytext);
+
+ if (g_lingo->_handlers.contains(yytext)) {
+ if (g_lingo->_handlers[yytext]->type == BLTIN && g_lingo->_handlers[yytext]->parens == false) {
+ if (g_lingo->_handlers[yytext]->nargs == 0) {
+ if (g_lingo->_handlers[yytext]->maxArgs == 0)
+ return BLTINNOARGS;
+ else if (g_lingo->_handlers[yytext]->maxArgs == 1)
+ return BLTINNOARGSORONE;
+ else
+ error("Incorrect setup for builtin: %s", yytext);
+ } else if (g_lingo->_handlers[yytext]->nargs == 1 &&
+ g_lingo->_handlers[yytext]->maxArgs == 1) {
+ return BLTINONEARG;
+ } else if (g_lingo->_handlers[yytext]->nargs == -1) {
+ return BLTINARGLIST;
+ } else {
+ error("Incorrect setup for builtin: %s", yytext);
+ }
+ }
+ }
+
+ return ID;
+ }
+{constfloat} { count(); yylval.f = atof(yytext); return FLOAT; }
+{constinteger} { count(); yylval.i = strtol(yytext, NULL, 10); return INT; }
+{operator} { count(); return *yytext; }
+{newline} { return '\n'; }
+{conststring} { count(); yylval.s = new Common::String(&yytext[1]); yylval.s->deleteLastChar(); return STRING; }
+.
+
+%%
+
+extern int yydebug;
+
+namespace Director {
+
+int Lingo::parse(const char *code) {
+ YY_BUFFER_STATE bp;
+
+ 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;
+}
+
+}