mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-08 11:57:25 +00:00
DIRECTOR: LINGO: Reimplement loops
This commit is contained in:
parent
03e6a56c5c
commit
d9a1057cd6
@ -35,6 +35,10 @@ struct PropertyNode;
|
|||||||
struct InstanceNode;
|
struct InstanceNode;
|
||||||
struct IfStmtNode;
|
struct IfStmtNode;
|
||||||
struct IfElseStmtNode;
|
struct IfElseStmtNode;
|
||||||
|
struct RepeatWhileNode;
|
||||||
|
struct RepeatWithToNode;
|
||||||
|
struct NextRepeatNode;
|
||||||
|
struct ExitRepeatNode;
|
||||||
struct IntNode;
|
struct IntNode;
|
||||||
struct FloatNode;
|
struct FloatNode;
|
||||||
struct SymbolNode;
|
struct SymbolNode;
|
||||||
@ -68,6 +72,10 @@ enum NodeType {
|
|||||||
kInstanceNode,
|
kInstanceNode,
|
||||||
kIfStmtNode,
|
kIfStmtNode,
|
||||||
kIfElseStmtNode,
|
kIfElseStmtNode,
|
||||||
|
kRepeatWhileNode,
|
||||||
|
kRepeatWithToNode,
|
||||||
|
kNextRepeatNode,
|
||||||
|
kExitRepeatNode,
|
||||||
kIntNode,
|
kIntNode,
|
||||||
kFloatNode,
|
kFloatNode,
|
||||||
kSymbolNode,
|
kSymbolNode,
|
||||||
@ -95,6 +103,10 @@ public:
|
|||||||
virtual void visitInstanceNode(InstanceNode *node) = 0;
|
virtual void visitInstanceNode(InstanceNode *node) = 0;
|
||||||
virtual void visitIfStmtNode(IfStmtNode *node) = 0;
|
virtual void visitIfStmtNode(IfStmtNode *node) = 0;
|
||||||
virtual void visitIfElseStmtNode(IfElseStmtNode *node) = 0;
|
virtual void visitIfElseStmtNode(IfElseStmtNode *node) = 0;
|
||||||
|
virtual void visitRepeatWhileNode(RepeatWhileNode *node) = 0;
|
||||||
|
virtual void visitRepeatWithToNode(RepeatWithToNode *node) = 0;
|
||||||
|
virtual void visitNextRepeatNode(NextRepeatNode *node) = 0;
|
||||||
|
virtual void visitExitRepeatNode(ExitRepeatNode *node) = 0;
|
||||||
virtual void visitIntNode(IntNode *node) = 0;
|
virtual void visitIntNode(IntNode *node) = 0;
|
||||||
virtual void visitFloatNode(FloatNode *node) = 0;
|
virtual void visitFloatNode(FloatNode *node) = 0;
|
||||||
virtual void visitSymbolNode(SymbolNode *node) = 0;
|
virtual void visitSymbolNode(SymbolNode *node) = 0;
|
||||||
@ -112,8 +124,9 @@ struct Node {
|
|||||||
NodeType type;
|
NodeType type;
|
||||||
bool isExpression;
|
bool isExpression;
|
||||||
bool isStatement;
|
bool isStatement;
|
||||||
|
bool isLoop;
|
||||||
|
|
||||||
Node(NodeType t) : type(t), isExpression(false), isStatement(false) {}
|
Node(NodeType t) : type(t), isExpression(false), isStatement(false), isLoop(false) {}
|
||||||
virtual ~Node() {}
|
virtual ~Node() {}
|
||||||
virtual void accept(NodeVisitor *visitor) = 0;
|
virtual void accept(NodeVisitor *visitor) = 0;
|
||||||
};
|
};
|
||||||
@ -136,6 +149,18 @@ struct StmtNode : Node {
|
|||||||
virtual ~StmtNode() {}
|
virtual ~StmtNode() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* LoopNode */
|
||||||
|
|
||||||
|
struct LoopNode : StmtNode {
|
||||||
|
Common::Array<uint> nextRepeats;
|
||||||
|
Common::Array<uint> exitRepeats;
|
||||||
|
|
||||||
|
LoopNode(NodeType t) : StmtNode(t) {
|
||||||
|
isLoop = true;
|
||||||
|
}
|
||||||
|
virtual ~LoopNode() {}
|
||||||
|
};
|
||||||
|
|
||||||
/* ScriptNode */
|
/* ScriptNode */
|
||||||
|
|
||||||
struct ScriptNode : Node {
|
struct ScriptNode : Node {
|
||||||
@ -281,6 +306,65 @@ struct IfElseStmtNode : StmtNode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* RepeatWhileNode */
|
||||||
|
|
||||||
|
struct RepeatWhileNode : LoopNode {
|
||||||
|
Node *cond;
|
||||||
|
NodeList *stmts;
|
||||||
|
|
||||||
|
RepeatWhileNode(Node *condIn, NodeList *stmtsIn)
|
||||||
|
: LoopNode(kRepeatWhileNode), cond(condIn), stmts(stmtsIn) {}
|
||||||
|
virtual ~RepeatWhileNode() {
|
||||||
|
delete cond;
|
||||||
|
deleteList(stmts);
|
||||||
|
}
|
||||||
|
virtual void accept(NodeVisitor *visitor) {
|
||||||
|
visitor->visitRepeatWhileNode(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* RepeatWithToNode */
|
||||||
|
|
||||||
|
struct RepeatWithToNode : LoopNode {
|
||||||
|
Common::String *var;
|
||||||
|
Node *start;
|
||||||
|
bool down;
|
||||||
|
Node *end;
|
||||||
|
NodeList *stmts;
|
||||||
|
|
||||||
|
RepeatWithToNode(Common::String *varIn, Node *startIn, bool downIn, Node *endIn, NodeList *stmtsIn)
|
||||||
|
: LoopNode(kRepeatWithToNode), var(varIn), start(startIn), down(downIn), end(endIn), stmts(stmtsIn) {}
|
||||||
|
virtual ~RepeatWithToNode() {
|
||||||
|
delete var;
|
||||||
|
delete start;
|
||||||
|
delete end;
|
||||||
|
deleteList(stmts);
|
||||||
|
}
|
||||||
|
virtual void accept(NodeVisitor *visitor) {
|
||||||
|
visitor->visitRepeatWithToNode(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NextRepeatNode */
|
||||||
|
|
||||||
|
struct NextRepeatNode : StmtNode {
|
||||||
|
NextRepeatNode() : StmtNode(kNextRepeatNode) {}
|
||||||
|
virtual ~NextRepeatNode() {}
|
||||||
|
virtual void accept(NodeVisitor *visitor) {
|
||||||
|
visitor->visitNextRepeatNode(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ExitRepeatNode */
|
||||||
|
|
||||||
|
struct ExitRepeatNode : StmtNode {
|
||||||
|
ExitRepeatNode() : StmtNode(kExitRepeatNode) {}
|
||||||
|
virtual ~ExitRepeatNode() {}
|
||||||
|
virtual void accept(NodeVisitor *visitor) {
|
||||||
|
visitor->visitExitRepeatNode(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* IntNode */
|
/* IntNode */
|
||||||
|
|
||||||
struct IntNode : ExprNode {
|
struct IntNode : ExprNode {
|
||||||
|
@ -66,6 +66,7 @@ LingoCompiler::LingoCompiler() {
|
|||||||
_lines[0] = _lines[1] = _lines[2] = nullptr;
|
_lines[0] = _lines[1] = _lines[2] = nullptr;
|
||||||
|
|
||||||
_inFactory = false;
|
_inFactory = false;
|
||||||
|
_currentLoop = nullptr;
|
||||||
|
|
||||||
_hadError = false;
|
_hadError = false;
|
||||||
}
|
}
|
||||||
@ -251,6 +252,15 @@ int LingoCompiler::codeFunc(Common::String *s, int numpar) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VarType LingoCompiler::globalCheck() {
|
||||||
|
// If in a definition, assume variables are local unless
|
||||||
|
// they were declared global with `global varname`
|
||||||
|
if (_indef) {
|
||||||
|
return kVarLocal;
|
||||||
|
}
|
||||||
|
return kVarGlobal;
|
||||||
|
}
|
||||||
|
|
||||||
void LingoCompiler::registerMethodVar(const Common::String &name, VarType type) {
|
void LingoCompiler::registerMethodVar(const Common::String &name, VarType type) {
|
||||||
if (!_methodVars->contains(name)) {
|
if (!_methodVars->contains(name)) {
|
||||||
(*_methodVars)[name] = type;
|
(*_methodVars)[name] = type;
|
||||||
@ -274,6 +284,24 @@ void LingoCompiler::registerFactory(Common::String &name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LingoCompiler::updateLoopJumps(uint nextTargetPos, uint exitTargetPos) {
|
||||||
|
if (!_currentLoop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (uint i = 0; i < _currentLoop->nextRepeats.size(); i++) {
|
||||||
|
uint nextRepeatPos = _currentLoop->nextRepeats[i];
|
||||||
|
inst jmpOffset = 0;
|
||||||
|
WRITE_UINT32(&jmpOffset, nextTargetPos - nextRepeatPos);
|
||||||
|
(*_currentAssembly)[nextRepeatPos + 1] = jmpOffset;
|
||||||
|
}
|
||||||
|
for (uint i = 0; i < _currentLoop->exitRepeats.size(); i++) {
|
||||||
|
uint exitRepeatPos = _currentLoop->exitRepeats[i];
|
||||||
|
inst jmpOffset = 0;
|
||||||
|
WRITE_UINT32(&jmpOffset, exitTargetPos - exitRepeatPos);
|
||||||
|
(*_currentAssembly)[exitRepeatPos + 1] = jmpOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LingoCompiler::parseMenu(const char *code) {
|
void LingoCompiler::parseMenu(const char *code) {
|
||||||
warning("STUB: parseMenu");
|
warning("STUB: parseMenu");
|
||||||
}
|
}
|
||||||
@ -433,6 +461,112 @@ void LingoCompiler::visitIfElseStmtNode(IfElseStmtNode *node) {
|
|||||||
(*_currentAssembly)[jmpPos + 1] = jmpOffset;
|
(*_currentAssembly)[jmpPos + 1] = jmpOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RepeatWhileNode */
|
||||||
|
|
||||||
|
void LingoCompiler::visitRepeatWhileNode(RepeatWhileNode *node) {
|
||||||
|
LoopNode *prevLoop = _currentLoop;
|
||||||
|
_currentLoop = node;
|
||||||
|
|
||||||
|
uint startPos = _currentAssembly->size();
|
||||||
|
compile(node->cond);
|
||||||
|
uint jzPos = _currentAssembly->size();
|
||||||
|
code2(LC::c_jumpifz, 0);
|
||||||
|
compileList(node->stmts);
|
||||||
|
uint jmpPos = _currentAssembly->size();
|
||||||
|
code2(LC::c_jump, 0);
|
||||||
|
uint endPos = _currentAssembly->size();
|
||||||
|
|
||||||
|
inst jzOffset = 0;
|
||||||
|
WRITE_UINT32(&jzOffset, endPos - jzPos);
|
||||||
|
(*_currentAssembly)[jzPos + 1] = jzOffset;
|
||||||
|
|
||||||
|
inst jmpOffset = 0;
|
||||||
|
WRITE_UINT32(&jmpOffset, startPos - jmpPos);
|
||||||
|
(*_currentAssembly)[jmpPos + 1] = jmpOffset;
|
||||||
|
|
||||||
|
updateLoopJumps(jmpPos, endPos);
|
||||||
|
_currentLoop = prevLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RepeatWithToNode */
|
||||||
|
|
||||||
|
void LingoCompiler::visitRepeatWithToNode(RepeatWithToNode *node) {
|
||||||
|
LoopNode *prevLoop = _currentLoop;
|
||||||
|
_currentLoop = node;
|
||||||
|
|
||||||
|
registerMethodVar(*node->var, globalCheck());
|
||||||
|
|
||||||
|
compile(node->start);
|
||||||
|
code1(LC::c_varpush);
|
||||||
|
codeString(node->var->c_str());
|
||||||
|
code1(LC::c_assign);
|
||||||
|
|
||||||
|
uint startPos = _currentAssembly->size();
|
||||||
|
code1(LC::c_eval);
|
||||||
|
codeString(node->var->c_str());
|
||||||
|
compile(node->end);
|
||||||
|
if (node->down) {
|
||||||
|
code1(LC::c_ge);
|
||||||
|
} else {
|
||||||
|
code1(LC::c_le);
|
||||||
|
}
|
||||||
|
uint jzPos = _currentAssembly->size();
|
||||||
|
code2(LC::c_jumpifz, 0);
|
||||||
|
|
||||||
|
compileList(node->stmts);
|
||||||
|
|
||||||
|
uint incrementPos = _currentAssembly->size();
|
||||||
|
code1(LC::c_eval);
|
||||||
|
codeString(node->var->c_str());
|
||||||
|
code1(LC::c_intpush);
|
||||||
|
codeInt(1);
|
||||||
|
if (node->down) {
|
||||||
|
code1(LC::c_sub);
|
||||||
|
} else {
|
||||||
|
code1(LC::c_add);
|
||||||
|
}
|
||||||
|
code1(LC::c_varpush);
|
||||||
|
codeString(node->var->c_str());
|
||||||
|
code1(LC::c_assign);
|
||||||
|
|
||||||
|
uint jmpPos = _currentAssembly->size();
|
||||||
|
code2(LC::c_jump, 0);
|
||||||
|
uint endPos = _currentAssembly->size();
|
||||||
|
|
||||||
|
inst jzOffset = 0;
|
||||||
|
WRITE_UINT32(&jzOffset, endPos - jzPos);
|
||||||
|
(*_currentAssembly)[jzPos + 1] = jzOffset;
|
||||||
|
|
||||||
|
inst jmpOffset = 0;
|
||||||
|
WRITE_UINT32(&jmpOffset, startPos - jmpPos);
|
||||||
|
(*_currentAssembly)[jmpPos + 1] = jmpOffset;
|
||||||
|
|
||||||
|
updateLoopJumps(incrementPos, endPos);
|
||||||
|
_currentLoop = prevLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NextRepeatNode */
|
||||||
|
|
||||||
|
void LingoCompiler::visitNextRepeatNode(NextRepeatNode *node) {
|
||||||
|
if (_currentLoop) {
|
||||||
|
_currentLoop->nextRepeats.push_back(_currentAssembly->size());
|
||||||
|
code2(LC::c_jump, 0);
|
||||||
|
} else {
|
||||||
|
warning("# LINGO: next repeat not inside repeat loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ExitRepeatNode */
|
||||||
|
|
||||||
|
void LingoCompiler::visitExitRepeatNode(ExitRepeatNode *node) {
|
||||||
|
if (_currentLoop) {
|
||||||
|
_currentLoop->exitRepeats.push_back(_currentAssembly->size());
|
||||||
|
code2(LC::c_jump, 0);
|
||||||
|
} else {
|
||||||
|
warning("# LINGO: exit repeat not inside repeat loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* IntNode */
|
/* IntNode */
|
||||||
|
|
||||||
void LingoCompiler::visitIntNode(IntNode *node) {
|
void LingoCompiler::visitIntNode(IntNode *node) {
|
||||||
|
@ -48,7 +48,9 @@ public:
|
|||||||
int codeInt(int val);
|
int codeInt(int val);
|
||||||
int codeString(const char *s);
|
int codeString(const char *s);
|
||||||
void registerFactory(Common::String &s);
|
void registerFactory(Common::String &s);
|
||||||
|
VarType globalCheck();
|
||||||
void registerMethodVar(const Common::String &name, VarType type);
|
void registerMethodVar(const Common::String &name, VarType type);
|
||||||
|
void updateLoopJumps(uint nextTargetPos, uint exitTargetPos);
|
||||||
|
|
||||||
LingoArchive *_assemblyArchive;
|
LingoArchive *_assemblyArchive;
|
||||||
ScriptContext *_assemblyContext;
|
ScriptContext *_assemblyContext;
|
||||||
@ -60,6 +62,7 @@ public:
|
|||||||
uint _bytenumber;
|
uint _bytenumber;
|
||||||
const char *_lines[3];
|
const char *_lines[3];
|
||||||
bool _inFactory;
|
bool _inFactory;
|
||||||
|
LoopNode *_currentLoop;
|
||||||
|
|
||||||
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVars;
|
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVars;
|
||||||
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVarsStash;
|
Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVarsStash;
|
||||||
@ -79,6 +82,10 @@ public:
|
|||||||
virtual void visitInstanceNode(InstanceNode *node);
|
virtual void visitInstanceNode(InstanceNode *node);
|
||||||
virtual void visitIfStmtNode(IfStmtNode *node);
|
virtual void visitIfStmtNode(IfStmtNode *node);
|
||||||
virtual void visitIfElseStmtNode(IfElseStmtNode *node);
|
virtual void visitIfElseStmtNode(IfElseStmtNode *node);
|
||||||
|
virtual void visitRepeatWhileNode(RepeatWhileNode *node);
|
||||||
|
virtual void visitRepeatWithToNode(RepeatWithToNode *node);
|
||||||
|
virtual void visitNextRepeatNode(NextRepeatNode *node);
|
||||||
|
virtual void visitExitRepeatNode(ExitRepeatNode *node);
|
||||||
virtual void visitIntNode(IntNode *node);
|
virtual void visitIntNode(IntNode *node);
|
||||||
virtual void visitFloatNode(FloatNode *node);
|
virtual void visitFloatNode(FloatNode *node);
|
||||||
virtual void visitSymbolNode(SymbolNode *node);
|
virtual void visitSymbolNode(SymbolNode *node);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -164,7 +164,7 @@ static void checkEnd(Common::String *token, Common::String *expect, bool require
|
|||||||
%type<idlist> idlist nonemptyidlist
|
%type<idlist> idlist nonemptyidlist
|
||||||
|
|
||||||
// STATEMENT
|
// STATEMENT
|
||||||
%type<node> stmt stmtoneliner proc definevars ifstmt ifelsestmt
|
%type<node> stmt stmtoneliner proc definevars ifstmt ifelsestmt loop
|
||||||
%type<nodelist> stmtlist nonemptystmtlist
|
%type<nodelist> stmtlist nonemptystmtlist
|
||||||
%type<node> stmtlistline
|
%type<node> stmtlistline
|
||||||
|
|
||||||
@ -354,6 +354,7 @@ nonemptyidlist: ID[item] {
|
|||||||
stmt: stmtoneliner
|
stmt: stmtoneliner
|
||||||
| ifstmt
|
| ifstmt
|
||||||
| ifelsestmt
|
| ifelsestmt
|
||||||
|
| loop
|
||||||
;
|
;
|
||||||
|
|
||||||
stmtoneliner: proc
|
stmtoneliner: proc
|
||||||
@ -362,6 +363,8 @@ stmtoneliner: proc
|
|||||||
|
|
||||||
proc: ID '(' exprlist[args] ')' '\n' { $$ = new CmdNode($ID, $args); }
|
proc: ID '(' exprlist[args] ')' '\n' { $$ = new CmdNode($ID, $args); }
|
||||||
| ID exprlist[args] '\n' { $$ = new CmdNode($ID, $args); }
|
| ID exprlist[args] '\n' { $$ = new CmdNode($ID, $args); }
|
||||||
|
| tNEXT tREPEAT { $$ = new NextRepeatNode(); }
|
||||||
|
| tEXIT tREPEAT { $$ = new ExitRepeatNode(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
definevars: tGLOBAL idlist '\n' { $$ = new GlobalNode($idlist); }
|
definevars: tGLOBAL idlist '\n' { $$ = new GlobalNode($idlist); }
|
||||||
@ -395,6 +398,14 @@ ifelsestmt: tIF expr tTHEN stmt[stmt1] tELSE stmt[stmt2] {
|
|||||||
$$ = new IfElseStmtNode($expr, $stmtlist1, $stmtlist2); }
|
$$ = new IfElseStmtNode($expr, $stmtlist1, $stmtlist2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
loop: tREPEAT tWHILE expr '\n' stmtlist tENDREPEAT '\n' {
|
||||||
|
$$ = new RepeatWhileNode($expr, $stmtlist); }
|
||||||
|
| tREPEAT tWITH ID tEQ expr[start] tTO expr[end] '\n' stmtlist tENDREPEAT '\n' {
|
||||||
|
$$ = new RepeatWithToNode($ID, $start, false, $end, $stmtlist); }
|
||||||
|
| tREPEAT tWITH ID tEQ expr[start] tDOWN tTO expr[end] '\n' stmtlist tENDREPEAT '\n' {
|
||||||
|
$$ = new RepeatWithToNode($ID, $start, true, $end, $stmtlist); }
|
||||||
|
;
|
||||||
|
|
||||||
stmtlist: /* empty */ { $$ = new NodeList; }
|
stmtlist: /* empty */ { $$ = new NodeList; }
|
||||||
| nonemptystmtlist
|
| nonemptystmtlist
|
||||||
;
|
;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user