mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-22 01:57:16 +00:00
DIRECTOR: LINGO: Reimplement loops
This commit is contained in:
parent
03e6a56c5c
commit
d9a1057cd6
@ -35,6 +35,10 @@ struct PropertyNode;
|
||||
struct InstanceNode;
|
||||
struct IfStmtNode;
|
||||
struct IfElseStmtNode;
|
||||
struct RepeatWhileNode;
|
||||
struct RepeatWithToNode;
|
||||
struct NextRepeatNode;
|
||||
struct ExitRepeatNode;
|
||||
struct IntNode;
|
||||
struct FloatNode;
|
||||
struct SymbolNode;
|
||||
@ -68,6 +72,10 @@ enum NodeType {
|
||||
kInstanceNode,
|
||||
kIfStmtNode,
|
||||
kIfElseStmtNode,
|
||||
kRepeatWhileNode,
|
||||
kRepeatWithToNode,
|
||||
kNextRepeatNode,
|
||||
kExitRepeatNode,
|
||||
kIntNode,
|
||||
kFloatNode,
|
||||
kSymbolNode,
|
||||
@ -95,6 +103,10 @@ public:
|
||||
virtual void visitInstanceNode(InstanceNode *node) = 0;
|
||||
virtual void visitIfStmtNode(IfStmtNode *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 visitFloatNode(FloatNode *node) = 0;
|
||||
virtual void visitSymbolNode(SymbolNode *node) = 0;
|
||||
@ -112,8 +124,9 @@ struct Node {
|
||||
NodeType type;
|
||||
bool isExpression;
|
||||
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 void accept(NodeVisitor *visitor) = 0;
|
||||
};
|
||||
@ -136,6 +149,18 @@ struct StmtNode : Node {
|
||||
virtual ~StmtNode() {}
|
||||
};
|
||||
|
||||
/* LoopNode */
|
||||
|
||||
struct LoopNode : StmtNode {
|
||||
Common::Array<uint> nextRepeats;
|
||||
Common::Array<uint> exitRepeats;
|
||||
|
||||
LoopNode(NodeType t) : StmtNode(t) {
|
||||
isLoop = true;
|
||||
}
|
||||
virtual ~LoopNode() {}
|
||||
};
|
||||
|
||||
/* ScriptNode */
|
||||
|
||||
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 */
|
||||
|
||||
struct IntNode : ExprNode {
|
||||
|
@ -66,6 +66,7 @@ LingoCompiler::LingoCompiler() {
|
||||
_lines[0] = _lines[1] = _lines[2] = nullptr;
|
||||
|
||||
_inFactory = false;
|
||||
_currentLoop = nullptr;
|
||||
|
||||
_hadError = false;
|
||||
}
|
||||
@ -251,6 +252,15 @@ int LingoCompiler::codeFunc(Common::String *s, int numpar) {
|
||||
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) {
|
||||
if (!_methodVars->contains(name)) {
|
||||
(*_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) {
|
||||
warning("STUB: parseMenu");
|
||||
}
|
||||
@ -433,6 +461,112 @@ void LingoCompiler::visitIfElseStmtNode(IfElseStmtNode *node) {
|
||||
(*_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 */
|
||||
|
||||
void LingoCompiler::visitIntNode(IntNode *node) {
|
||||
|
@ -48,7 +48,9 @@ public:
|
||||
int codeInt(int val);
|
||||
int codeString(const char *s);
|
||||
void registerFactory(Common::String &s);
|
||||
VarType globalCheck();
|
||||
void registerMethodVar(const Common::String &name, VarType type);
|
||||
void updateLoopJumps(uint nextTargetPos, uint exitTargetPos);
|
||||
|
||||
LingoArchive *_assemblyArchive;
|
||||
ScriptContext *_assemblyContext;
|
||||
@ -60,6 +62,7 @@ public:
|
||||
uint _bytenumber;
|
||||
const char *_lines[3];
|
||||
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> *_methodVarsStash;
|
||||
@ -79,6 +82,10 @@ public:
|
||||
virtual void visitInstanceNode(InstanceNode *node);
|
||||
virtual void visitIfStmtNode(IfStmtNode *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 visitFloatNode(FloatNode *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
|
||||
|
||||
// STATEMENT
|
||||
%type<node> stmt stmtoneliner proc definevars ifstmt ifelsestmt
|
||||
%type<node> stmt stmtoneliner proc definevars ifstmt ifelsestmt loop
|
||||
%type<nodelist> stmtlist nonemptystmtlist
|
||||
%type<node> stmtlistline
|
||||
|
||||
@ -354,6 +354,7 @@ nonemptyidlist: ID[item] {
|
||||
stmt: stmtoneliner
|
||||
| ifstmt
|
||||
| ifelsestmt
|
||||
| loop
|
||||
;
|
||||
|
||||
stmtoneliner: proc
|
||||
@ -362,6 +363,8 @@ stmtoneliner: proc
|
||||
|
||||
proc: 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); }
|
||||
@ -395,6 +398,14 @@ ifelsestmt: tIF expr tTHEN stmt[stmt1] tELSE stmt[stmt2] {
|
||||
$$ = 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; }
|
||||
| nonemptystmtlist
|
||||
;
|
||||
|
Loading…
x
Reference in New Issue
Block a user