1
0

Implement GOSUB/GOTO x:@LABEL

This commit is contained in:
otya128
2016-12-29 16:16:56 +09:00
parent 5c6ec3e9e0
commit abdd6cdc8c
3 changed files with 71 additions and 17 deletions

View File

@@ -372,7 +372,21 @@ class VM
} }
bool chklabel(wstring label) bool chklabel(wstring label)
{ {
if (label in currentSlot.globalLabel) auto name = parse(label);
VMSlot slot;
if (name.hasSlot)
{
if (!checkSlotNumber(name.slot))
{
return false;
}
slot = slots[name.slot];
}
else
{
slot = currentSlot;
}
if (label in slot.globalLabel)
return true; return true;
if (currentFunction && label in currentFunction.label) if (currentFunction && label in currentFunction.label)
return true; return true;
@@ -982,23 +996,36 @@ class GotoFalse : Code
} }
class GotoExpr : Code class GotoExpr : Code
{ {
this()
{
}
override void execute(VM vm) override void execute(VM vm)
{ {
Value label; Value label;
vm.pop(label); vm.pop(label);
if(label.isString) if(label.isString)
{ {
if (label.castDString.length == 0)
throw new InternalError();
int pc; int pc;
if (vm.currentFunction) auto name = VM.parse(label.castDString);
if (name.name[0] != '@')
{ {
pc = vm.currentFunction.label.get(label.castDString, int.min); throw new IllegalSymbolString();
}
if (name.name.length == 0 || name.hasSlot)
{
if (!vm.checkSlotNumber(name.slot))
{
throw new IllegalSymbolString();
}
vm.setCurrentSlot(name.slot);
}
if (!name.hasSlot && vm.currentFunction)
{
vm.setCurrentSlot(vm.currentFunction.slot.index);
pc = vm.currentFunction.label.get(name.name, int.min);
} }
else else
{ {
pc = vm.currentSlot.globalLabel.get(label.castDString, int.min); pc = vm.currentSlot.globalLabel.get(name.name, int.min);
} }
if (pc == int.min) if (pc == int.min)
{ {
@@ -1048,27 +1075,38 @@ class GosubS : Code
} }
class GosubExpr : Code class GosubExpr : Code
{ {
Scope sc;
this(Scope sc)
{
this.sc = sc;
}
override void execute(VM vm) override void execute(VM vm)
{ {
Value label; Value label;
vm.pop(label); vm.pop(label);
if(label.isString) if(label.isString)
{ {
if (label.castDString.length == 0)
throw new InternalError();
int pc;
auto name = VM.parse(label.castDString);
if (name.name.length == 0 || name.name[0] != '@')
{
throw new IllegalSymbolString();
}
vm.pushBackTrace(label.castDString); vm.pushBackTrace(label.castDString);
vm.pushpc; vm.pushpc;
int pc; if (name.hasSlot)
if (sc && sc.func)
{ {
pc = sc.func.label.get(label.castDString, int.min); if (!vm.checkSlotNumber(name.slot))
{
throw new IllegalSymbolString();
}
vm.setCurrentSlot(name.slot);
}
if (!name.hasSlot && vm.currentFunction)
{
vm.setCurrentSlot(vm.currentFunction.slot.index);
pc = vm.currentFunction.label.get(name.name, int.min);
} }
else else
{ {
pc = vm.currentSlot.globalLabel.get(label.castDString, int.min); pc = vm.currentSlot.globalLabel.get(name.name, int.min);
} }
if (pc == int.min) if (pc == int.min)
{ {

View File

@@ -1032,7 +1032,7 @@ class Compiler
else else
{ {
compileExpression(gosub.labelexpr, s); compileExpression(gosub.labelexpr, s);
genCode(new GosubExpr(s)); genCode(new GosubExpr());
} }
} }
break; break;

View File

@@ -38,6 +38,14 @@ class SmileBasicError : Exception
return message2; return message2;
} }
} }
class InternalError : SmileBasicError
{
this()
{
this.errnum = 1;
super("Internal Error");
}
}
class SyntaxError : SmileBasicError class SyntaxError : SmileBasicError
{ {
this() this()
@@ -203,6 +211,14 @@ class SubscriptOutOfRange : SmileBasicError
super("Subscript out of range(" ~ func ~ ":" ~ arg.to!string ~ ")"); super("Subscript out of range(" ~ func ~ ":" ~ arg.to!string ~ ")");
} }
} }
class IllegalSymbolString : SmileBasicError
{
this()
{
this.errnum = 34;
super("Illegal symbol string");
}
}
class UsePRGEDITBeforeAnyPRGFunction : SmileBasicError class UsePRGEDITBeforeAnyPRGFunction : SmileBasicError
{ {
this(string func) this(string func)