DIRECTOR: LINGO: Use visitor pattern for AST traversal

Compile functions now belong to LingoCompile.
This commit is contained in:
djsrv 2021-06-15 22:57:14 -04:00 committed by D.J. Servilla
parent 0a708b9c8f
commit 38e8068180
5 changed files with 276 additions and 215 deletions

View File

@ -1,192 +0,0 @@
/* 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.
*
*/
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-codegen.h"
#include "director/lingo/lingo-object.h"
namespace Director {
/* ScriptNode */
void ScriptNode::compile() {
for (uint i = 0; i < nodes->size(); i++) {
(*nodes)[i]->compile();
}
}
/* FactoryNode */
void FactoryNode::compile() {
g_lingo->_compiler->_inFactory = true;
ScriptContext *mainContext = g_lingo->_compiler->_assemblyContext;
g_lingo->_compiler->_assemblyContext = new ScriptContext(mainContext->getName(), mainContext->_archive, mainContext->_scriptType, mainContext->_id);
g_lingo->_compiler->codeFactory(*name);
for (uint i = 0; i < methods->size(); i++) {
(*methods)[i]->compile();
}
g_lingo->_compiler->_inFactory = false;
g_lingo->_compiler->_assemblyContext = mainContext;
}
/* HandlerNode */
void HandlerNode::compile() {
g_lingo->_compiler->_indef = true;
VarTypeHash *mainMethodVars = g_lingo->_compiler->_methodVars;
g_lingo->_compiler->_methodVars = new VarTypeHash;
for (VarTypeHash::iterator i = mainMethodVars->begin(); i != mainMethodVars->end(); ++i) {
if (i->_value == kVarGlobal || i->_value == kVarProperty)
(*g_lingo->_compiler->_methodVars)[i->_key] = i->_value;
}
if (g_lingo->_compiler->_inFactory) {
for (DatumHash::iterator i = g_lingo->_compiler->_assemblyContext->_properties.begin(); i != g_lingo->_compiler->_assemblyContext->_properties.end(); ++i) {
(*g_lingo->_compiler->_methodVars)[i->_key] = kVarInstance;
}
}
for (uint i = 0; i < args->size(); i++) { // TODO: eliminate argstack
g_lingo->_compiler->codeArg((*args)[i]);
}
uint start = g_lingo->_compiler->_currentAssembly->size(); // TODO: should always be zero
for (uint i = 0; i < stmts->size(); i++) {
(*stmts)[i]->compile();
}
g_lingo->_compiler->code1(LC::c_procret);
g_lingo->_compiler->codeDefine(*name, start, args->size());
g_lingo->_compiler->clearArgStack();
g_lingo->_compiler->_indef = false;
delete g_lingo->_compiler->_methodVars;
g_lingo->_compiler->_methodVars = mainMethodVars;
}
/* CmdNode */
void CmdNode::compile() {
for (uint i = 0; i < args->size(); i++) {
(*args)[i]->compile();
}
g_lingo->_compiler->codeCmd(name, args->size());
}
/* GlobalNode */
void GlobalNode::compile() {
for (uint i = 0; i < names->size(); i++) {
g_lingo->_compiler->registerMethodVar(*(*names)[i], kVarGlobal);
}
}
/* PropertyNode */
void PropertyNode::compile() {
for (uint i = 0; i < names->size(); i++) {
g_lingo->_compiler->registerMethodVar(*(*names)[i], kVarProperty);
}
}
/* InstanceNode */
void InstanceNode::compile() {
for (uint i = 0; i < names->size(); i++) {
g_lingo->_compiler->registerMethodVar(*(*names)[i], kVarInstance);
}
}
/* IntNode */
void IntNode::compile() {
g_lingo->_compiler->code1(LC::c_intpush);
g_lingo->_compiler->codeInt(val);
}
/* FloatNode */
void FloatNode::compile() {
g_lingo->_compiler->code1(LC::c_floatpush);
g_lingo->_compiler->codeFloat(val);
}
/* SymbolNode */
void SymbolNode::compile() {
g_lingo->_compiler->code1(LC::c_symbolpush);
g_lingo->_compiler->codeString(val->c_str());
}
/* StringNode */
void StringNode::compile() {
g_lingo->_compiler->code1(LC::c_stringpush);
g_lingo->_compiler->codeString(val->c_str());
}
/* FuncNode */
void FuncNode::compile() {
for (uint i = 0; i < args->size(); i++) {
(*args)[i]->compile();
}
g_lingo->_compiler->codeFunc(name, args->size());
}
/* VarNode */
void VarNode::compile() {
if (g_lingo->_builtinConsts.contains(*name)) {
g_lingo->_compiler->code1(LC::c_constpush);
} else {
g_lingo->_compiler->code1(LC::c_eval);
}
g_lingo->_compiler->codeString(name->c_str());
}
/* ParensNode */
void ParensNode::compile() {
expr->compile();
}
/* UnaryOpNode */
void UnaryOpNode::compile() {
arg->compile();
g_lingo->_compiler->code1(op);
}
/* BinaryOpNode */
void BinaryOpNode::compile() {
a->compile();
b->compile();
g_lingo->_compiler->code1(op);
}
} // End of namespace Director

View File

@ -26,6 +26,22 @@
namespace Director {
struct Node;
struct ScriptNode;
struct FactoryNode;
struct HandlerNode;
struct CmdNode;
struct GlobalNode;
struct PropertyNode;
struct InstanceNode;
struct IntNode;
struct FloatNode;
struct SymbolNode;
struct StringNode;
struct FuncNode;
struct VarNode;
struct ParensNode;
struct UnaryOpNode;
struct BinaryOpNode;
typedef Common::Array<Node *> NodeList;
typedef Common::Array<Common::String *> IDList;
@ -59,6 +75,31 @@ enum NodeType {
kBinaryOpNode
};
/* NodeVisitor */
class NodeVisitor {
public:
NodeVisitor() {}
virtual ~NodeVisitor() {}
virtual void visitScriptNode(ScriptNode *node) = 0;
virtual void visitFactoryNode(FactoryNode *node) = 0;
virtual void visitHandlerNode(HandlerNode *node) = 0;
virtual void visitCmdNode(CmdNode *node) = 0;
virtual void visitGlobalNode(GlobalNode *node) = 0;
virtual void visitPropertyNode(PropertyNode *node) = 0;
virtual void visitInstanceNode(InstanceNode *node) = 0;
virtual void visitIntNode(IntNode *node) = 0;
virtual void visitFloatNode(FloatNode *node) = 0;
virtual void visitSymbolNode(SymbolNode *node) = 0;
virtual void visitStringNode(StringNode *node) = 0;
virtual void visitFuncNode(FuncNode *node) = 0;
virtual void visitVarNode(VarNode *node) = 0;
virtual void visitParensNode(ParensNode *node) = 0;
virtual void visitUnaryOpNode(UnaryOpNode *node) = 0;
virtual void visitBinaryOpNode(BinaryOpNode *node) = 0;
};
/* Node */
struct Node {
@ -67,8 +108,8 @@ struct Node {
bool isStatement;
Node(NodeType t) : type(t), isExpression(false), isStatement(false) {}
virtual ~Node() = default;
virtual void compile() {}
virtual ~Node() {}
virtual void accept(NodeVisitor *visitor) = 0;
};
/* ExprNode */
@ -77,7 +118,7 @@ struct ExprNode : Node {
ExprNode(NodeType t) : Node(t) {
isExpression = true;
}
virtual ~ExprNode() = default;
virtual ~ExprNode() {}
};
/* StmtNode */
@ -86,7 +127,7 @@ struct StmtNode : Node {
StmtNode(NodeType t) : Node(t) {
isStatement = true;
}
virtual ~StmtNode() = default;
virtual ~StmtNode() {}
};
/* ScriptNode */
@ -98,7 +139,9 @@ struct ScriptNode : Node {
virtual ~ScriptNode() {
deleteList(nodes);
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitScriptNode(this);
}
};
/* FactoryNode */
@ -113,7 +156,9 @@ struct FactoryNode : Node {
delete name;
deleteList(methods);
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitFactoryNode(this);
}
};
/* HandlerNode */
@ -130,7 +175,9 @@ struct HandlerNode : Node {
deleteList(args);
deleteList(stmts);
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitHandlerNode(this);
}
};
/* CmdNode */
@ -145,7 +192,9 @@ struct CmdNode : StmtNode {
delete name;
deleteList(args);
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitCmdNode(this);
}
};
/* GlobalNode */
@ -157,7 +206,9 @@ struct GlobalNode : StmtNode {
virtual ~GlobalNode() {
delete names;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitGlobalNode(this);
}
};
/* PropertyNode */
@ -169,7 +220,9 @@ struct PropertyNode : StmtNode {
virtual ~PropertyNode() {
delete names;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitPropertyNode(this);
}
};
/* InstanceNode */
@ -181,7 +234,9 @@ struct InstanceNode : StmtNode {
virtual ~InstanceNode() {
delete names;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitInstanceNode(this);
}
};
/* IntNode */
@ -191,7 +246,9 @@ struct IntNode : ExprNode {
IntNode(int valIn) : ExprNode(kIntNode), val(valIn) {}
virtual ~IntNode() = default;
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitIntNode(this);
}
};
/* FloatNode */
@ -201,7 +258,9 @@ struct FloatNode : ExprNode {
FloatNode(double valIn) : ExprNode(kFloatNode), val(valIn) {}
virtual ~FloatNode() = default;
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitFloatNode(this);
}
};
/* SymbolNode */
@ -213,7 +272,9 @@ struct SymbolNode : ExprNode {
virtual ~SymbolNode() {
delete val;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitSymbolNode(this);
}
};
/* StringNode */
@ -225,7 +286,9 @@ struct StringNode : ExprNode {
virtual ~StringNode() {
delete val;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitStringNode(this);
}
};
/* FuncNode */
@ -240,7 +303,9 @@ struct FuncNode : StmtNode {
delete name;
deleteList(args);
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitFuncNode(this);
}
};
/* VarNode */
@ -252,7 +317,9 @@ struct VarNode : ExprNode {
virtual ~VarNode() {
delete name;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitVarNode(this);
}
};
/* ParensNode */
@ -264,7 +331,9 @@ struct ParensNode : ExprNode {
virtual ~ParensNode() {
delete expr;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitParensNode(this);
}
};
/* UnaryOpNode */
@ -277,7 +346,9 @@ struct UnaryOpNode : ExprNode {
virtual ~UnaryOpNode() {
delete arg;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitUnaryOpNode(this);
}
};
/* BinaryOpNode */
@ -292,7 +363,9 @@ struct BinaryOpNode : ExprNode {
delete a;
delete b;
}
virtual void compile();
virtual void accept(NodeVisitor *visitor) {
visitor->visitBinaryOpNode(this);
}
};
} // End of namespace Director

View File

@ -103,7 +103,7 @@ ScriptContext *LingoCompiler::compileLingo(const char *code, LingoArchive *archi
// Generate bytecode
if (_assemblyAST) {
_assemblyAST->compile();
_assemblyAST->accept(this);
}
// for D4 and above, there usually won't be any code left.
@ -374,4 +374,165 @@ void LingoCompiler::parseMenu(const char *code) {
warning("STUB: parseMenu");
}
/* ScriptNode */
void LingoCompiler::visitScriptNode(ScriptNode *node) {
for (uint i = 0; i < node->nodes->size(); i++) {
(*node->nodes)[i]->accept(this);
}
}
/* FactoryNode */
void LingoCompiler::visitFactoryNode(FactoryNode *node) {
_inFactory = true;
ScriptContext *mainContext = _assemblyContext;
_assemblyContext = new ScriptContext(mainContext->getName(), mainContext->_archive, mainContext->_scriptType, mainContext->_id);
codeFactory(*node->name);
for (uint i = 0; i < node->methods->size(); i++) {
(*node->methods)[i]->accept(this);
}
_inFactory = false;
_assemblyContext = mainContext;
}
/* HandlerNode */
void LingoCompiler::visitHandlerNode(HandlerNode *node) {
_indef = true;
VarTypeHash *mainMethodVars = _methodVars;
_methodVars = new VarTypeHash;
for (VarTypeHash::iterator i = mainMethodVars->begin(); i != mainMethodVars->end(); ++i) {
if (i->_value == kVarGlobal || i->_value == kVarProperty)
(*_methodVars)[i->_key] = i->_value;
}
if (_inFactory) {
for (DatumHash::iterator i = _assemblyContext->_properties.begin(); i != _assemblyContext->_properties.end(); ++i) {
(*_methodVars)[i->_key] = kVarInstance;
}
}
for (uint i = 0; i < node->args->size(); i++) { // TODO: eliminate argstack
codeArg((*node->args)[i]);
}
uint start = _currentAssembly->size(); // TODO: should always be zero
for (uint i = 0; i < node->stmts->size(); i++) {
(*node->stmts)[i]->accept(this);
}
code1(LC::c_procret);
codeDefine(*node->name, start, node->args->size());
clearArgStack();
_indef = false;
delete _methodVars;
_methodVars = mainMethodVars;
}
/* CmdNode */
void LingoCompiler::visitCmdNode(CmdNode *node) {
for (uint i = 0; i < node->args->size(); i++) {
(*node->args)[i]->accept(this);
}
codeCmd(node->name, node->args->size());
}
/* GlobalNode */
void LingoCompiler::visitGlobalNode(GlobalNode *node) {
for (uint i = 0; i < node->names->size(); i++) {
registerMethodVar(*(*node->names)[i], kVarGlobal);
}
}
/* PropertyNode */
void LingoCompiler::visitPropertyNode(PropertyNode *node) {
for (uint i = 0; i < node->names->size(); i++) {
registerMethodVar(*(*node->names)[i], kVarProperty);
}
}
/* InstanceNode */
void LingoCompiler::visitInstanceNode(InstanceNode *node) {
for (uint i = 0; i < node->names->size(); i++) {
registerMethodVar(*(*node->names)[i], kVarInstance);
}
}
/* IntNode */
void LingoCompiler::visitIntNode(IntNode *node) {
code1(LC::c_intpush);
codeInt(node->val);
}
/* FloatNode */
void LingoCompiler::visitFloatNode(FloatNode *node) {
code1(LC::c_floatpush);
codeFloat(node->val);
}
/* SymbolNode */
void LingoCompiler::visitSymbolNode(SymbolNode *node) {
code1(LC::c_symbolpush);
codeString(node->val->c_str());
}
/* StringNode */
void LingoCompiler::visitStringNode(StringNode *node) {
code1(LC::c_stringpush);
codeString(node->val->c_str());
}
/* FuncNode */
void LingoCompiler::visitFuncNode(FuncNode *node) {
for (uint i = 0; i < node->args->size(); i++) {
(*node->args)[i]->accept(this);
}
codeFunc(node->name, node->args->size());
}
/* VarNode */
void LingoCompiler::visitVarNode(VarNode *node) {
if (g_lingo->_builtinConsts.contains(*node->name)) {
code1(LC::c_constpush);
} else {
code1(LC::c_eval);
}
codeString(node->name->c_str());
}
/* ParensNode */
void LingoCompiler::visitParensNode(ParensNode *node) {
node->expr->accept(this);
}
/* UnaryOpNode */
void LingoCompiler::visitUnaryOpNode(UnaryOpNode *node) {
node->arg->accept(this);
code1(node->op);
}
/* BinaryOpNode */
void LingoCompiler::visitBinaryOpNode(BinaryOpNode *node) {
node->a->accept(this);
node->b->accept(this);
code1(node->op);
}
} // End of namespace Director

View File

@ -25,12 +25,14 @@
#include "director/types.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-ast.h"
namespace Director {
class LingoCompiler {
class LingoCompiler : NodeVisitor {
public:
LingoCompiler();
virtual ~LingoCompiler() {}
ScriptContext *compileAnonymous(const char *code);
ScriptContext *compileLingo(const char *code, LingoArchive *archive, ScriptType type, uint16 id, const Common::String &scriptName, bool anonyomous = false);
@ -74,6 +76,24 @@ public:
bool _hadError;
public:
virtual void visitScriptNode(ScriptNode *node);
virtual void visitFactoryNode(FactoryNode *node);
virtual void visitHandlerNode(HandlerNode *node);
virtual void visitCmdNode(CmdNode *node);
virtual void visitGlobalNode(GlobalNode *node);
virtual void visitPropertyNode(PropertyNode *node);
virtual void visitInstanceNode(InstanceNode *node);
virtual void visitIntNode(IntNode *node);
virtual void visitFloatNode(FloatNode *node);
virtual void visitSymbolNode(SymbolNode *node);
virtual void visitStringNode(StringNode *node);
virtual void visitFuncNode(FuncNode *node);
virtual void visitVarNode(VarNode *node);
virtual void visitParensNode(ParensNode *node);
virtual void visitUnaryOpNode(UnaryOpNode *node);
virtual void visitBinaryOpNode(BinaryOpNode *node);
private:
int parse(const char *code);
void parseMenu(const char *code);

View File

@ -23,7 +23,6 @@ MODULE_OBJS = \
util.o \
window.o \
lingo/lingo.o \
lingo/lingo-ast.o \
lingo/lingo-builtins.o \
lingo/lingo-bytecode.o \
lingo/lingo-code.o \