Browse Source

Reached turing completeness

master
Ludovic 'Archivist' Lagouardette 3 years ago
parent
commit
f56553f2da
3 changed files with 52 additions and 7 deletions
  1. +2
    -2
      Functions/Goto.cs
  2. +44
    -4
      Parser.cs
  3. +6
    -1
      Test.basic

+ 2
- 2
Functions/Goto.cs View File

@ -9,7 +9,7 @@ namespace SuperBASIC.Functions
public float Apply(List<BasicNumber> arguments) public float Apply(List<BasicNumber> arguments)
{ {
// Substract its own arity +1 // Substract its own arity +1
arguments[0].runtime.pc = (int)arguments[0].GetOperand() - 2;
arguments[0].runtime.pc = (int)arguments[0] - 2;
return 0f; return 0f;
} }
} }
@ -19,7 +19,7 @@ namespace SuperBASIC.Functions
{ {
if(arguments[0] == 0) if(arguments[0] == 0)
// Substract its own arity +1 // Substract its own arity +1
arguments[1].runtime.pc = (int)arguments[1].GetOperand() - 3;
arguments[1].runtime.pc = (int)arguments[1] - 3;
return 0f; return 0f;
} }
} }

+ 44
- 4
Parser.cs View File

@ -22,6 +22,8 @@ namespace SuperBASIC
readonly Library library; readonly Library library;
readonly Runtime runtime; readonly Runtime runtime;
Dictionary<string, int> namedLabels;
List<Tuple<string, int>> positionedLabels;
public Parser(Runtime rt) public Parser(Runtime rt)
{ {
runtime = rt; runtime = rt;
@ -78,7 +80,12 @@ namespace SuperBASIC
} }
else else
#endif #endif
if (elem == "$")
if (namedLabels.ContainsKey(elem))
{
positionedLabels.Add(new Tuple<string, int>(elem, c.bytecode.Count));
c.bytecode.Add(new BasicNumber(runtime, (float)namedLabels[elem]));
}
else if (elem == "$")
{ {
c.bytecode.Add(new BasicNumber(runtime)); c.bytecode.Add(new BasicNumber(runtime));
} }
@ -117,6 +124,8 @@ namespace SuperBASIC
List<string> codeLines = new List<string>(); List<string> codeLines = new List<string>();
List<int> lineSpans = new List<int>(); List<int> lineSpans = new List<int>();
Stack<FlowControlTag> labelStack = new Stack<FlowControlTag>(); Stack<FlowControlTag> labelStack = new Stack<FlowControlTag>();
namedLabels = new Dictionary<string, int>();
positionedLabels = new List<Tuple<string, int>>();
int a = 0; int a = 0;
foreach (string line in sourceLines) foreach (string line in sourceLines)
@ -134,6 +143,23 @@ namespace SuperBASIC
} }
} }
for (int idx = 0; idx < codeLines.Count; idx++)
{
string line = codeLines[idx];
var components = line.Split(' ');
if (components[0] == "LABEL")
{
if (components.Length != 2)
{
int lineIndex = 0;
foreach (int cnt in lineSpans.GetRange(0, idx + 1)) lineIndex += cnt;
throw new ParseException($"Bad LABEL statement\n\tat line {lineIndex}");
}
namedLabels[components[1]] = -1;
}
}
for (int idx = 0; idx < codeLines.Count; idx++) for (int idx = 0; idx < codeLines.Count; idx++)
{ {
string line = codeLines[idx]; string line = codeLines[idx];
@ -149,6 +175,15 @@ namespace SuperBASIC
labelStack.Push(label); labelStack.Push(label);
ParseExpression(c, components[1..], idx, lineSpans); ParseExpression(c, components[1..], idx, lineSpans);
break; break;
case "LABEL":
if (components.Length != 2)
{
int lineIndex = 0;
foreach (int cnt in lineSpans.GetRange(0, idx + 1)) lineIndex += cnt;
throw new ParseException($"Bad LABEL statement\n\tat line {lineIndex}");
}
namedLabels[components[1]] = c.bytecode.Count;
break;
case "THEN": case "THEN":
// Role: Jumps to the far block if false // Role: Jumps to the far block if false
// 1. Adds the label to update the destination // 1. Adds the label to update the destination
@ -181,7 +216,7 @@ namespace SuperBASIC
c.bytecode.Add(new BasicNumber(runtime, library.nameResolution["GOTO"])); c.bytecode.Add(new BasicNumber(runtime, library.nameResolution["GOTO"]));
c.bytecode.Add(new BasicNumber(runtime, 0f)); c.bytecode.Add(new BasicNumber(runtime, 0f));
//4. Place the THEN destination after the GOTO //4. Place the THEN destination after the GOTO
c.bytecode[label.index+2] = new BasicNumber(runtime, c.bytecode.Count);
c.bytecode[label.index+2] = new BasicNumber(runtime, p">(float)c.bytecode.Count);
break; break;
case "ENDIF": case "ENDIF":
//Role: Destination if depending on what is skipped //Role: Destination if depending on what is skipped
@ -189,12 +224,12 @@ namespace SuperBASIC
if (label.ctrl == Controls.Else) if (label.ctrl == Controls.Else)
{ {
//Case 1: update the GOTO //Case 1: update the GOTO
c.bytecode[label.index + 1] = new BasicNumber(runtime, c.bytecode.Count);
c.bytecode[label.index + 1] = new BasicNumber(runtime, p">(float)c.bytecode.Count);
} }
else if (label.ctrl == Controls.Then) else if (label.ctrl == Controls.Then)
{ {
//Case 2: update the JZ //Case 2: update the JZ
c.bytecode[label.index + 2] = new BasicNumber(runtime, c.bytecode.Count);
c.bytecode[label.index + 2] = new BasicNumber(runtime, p">(float)c.bytecode.Count);
} }
else else
{ {
@ -215,6 +250,11 @@ namespace SuperBASIC
break; break;
} }
} }
foreach(var lbl in positionedLabels)
{
c.bytecode[lbl.Item2] = new BasicNumber(runtime, (float)namedLabels[lbl.Item1]);
}
return c; return c;
} }
} }

+ 6
- 1
Test.basic View File

@ -4,6 +4,11 @@ MULTIPLY $ $
IF COMPARE $ 7.3890557 IF COMPARE $ 7.3890557
THEN THEN
PRINT 25 PRINT 25
GOTO end
ELSE ELSE
PRINT 10 PRINT 10
ENDIF
ENDIF
LABEL loop
PRINT 50
GOTO loop
LABEL end

Loading…
Cancel
Save