Add capability for For Loop processing
Some checks failed
Build .NET Project / build (push) Has been cancelled
Some checks failed
Build .NET Project / build (push) Has been cancelled
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
|
||||
// FileName : Parser.cs
|
||||
// Author : Sean Kessler
|
||||
|
||||
@@ -34,7 +35,7 @@ namespace Axiom.Interpreter
|
||||
private String stringValue;
|
||||
private bool strictStatementMode=false; // is StrictStatementMode is true then the parser will return an error if there is not at least one statement processed.
|
||||
private Stack<long> breakStack = new Stack<long>(); // when we encounter a break statement we need to record the address of the code pointer
|
||||
private Stack<bool> whileStack = new Stack<bool>(); // when we encounter a while statement we need to record the event so that we can validate any break statements
|
||||
private Stack<bool> loopStack = new Stack<bool>(); // when we encounter a loop (while/for) statement we need to record the event so that we can validate any break statements
|
||||
|
||||
public Parser(BinaryReader binaryReader, BinaryWriter binaryWriter, SymbolTable symbolTable)
|
||||
: base(binaryReader, binaryWriter)
|
||||
@@ -135,11 +136,16 @@ namespace Axiom.Interpreter
|
||||
BreakStatement();
|
||||
StatementNumber++;
|
||||
}
|
||||
else if (Scanner.ScanSymbols.while1.Equals(currentSymbolType))
|
||||
else if (Scanner.ScanSymbols.while1.Equals(currentSymbolType))
|
||||
{
|
||||
WhileStatement();
|
||||
StatementNumber++;
|
||||
}
|
||||
else if (Scanner.ScanSymbols.for1.Equals(currentSymbolType))
|
||||
{
|
||||
ForStatement();
|
||||
StatementNumber++;
|
||||
}
|
||||
else if (SymbolIn(termSymbols))
|
||||
{
|
||||
Term();
|
||||
@@ -157,6 +163,7 @@ namespace Axiom.Interpreter
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.endtext1));
|
||||
return;
|
||||
}
|
||||
|
||||
public void DeclarationStatement()
|
||||
{
|
||||
bool moreDeclarations = true;
|
||||
@@ -178,21 +185,24 @@ namespace Axiom.Interpreter
|
||||
}
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.variable1));
|
||||
}
|
||||
|
||||
public void DirectiveClearModified()
|
||||
{
|
||||
Emit(Parser.ParserSymbols.directive_clear_modified2);
|
||||
Expect(Scanner.ScanSymbols.directive_clear_modified1);
|
||||
}
|
||||
|
||||
public void ParseLiteral()
|
||||
{
|
||||
Emit(Parser.ParserSymbols.push2, stringValue);
|
||||
Expect(Scanner.ScanSymbols.literal1);
|
||||
}
|
||||
|
||||
public void BreakStatement()
|
||||
{
|
||||
if(0.Equals(whileStack.Count))
|
||||
if(0.Equals(loopStack.Count))
|
||||
{
|
||||
SyntaxError("Encountered 'break' without 'while'");
|
||||
SyntaxError("Encountered 'break' without 'while'/'for'");
|
||||
}
|
||||
if(breakStack.Count>0)
|
||||
{
|
||||
@@ -205,6 +215,267 @@ namespace Axiom.Interpreter
|
||||
breakStack.Push(CodePointer());
|
||||
Expect(Scanner.ScanSymbols.break1);
|
||||
}
|
||||
// ********************************************************************************************************************************
|
||||
// *************************************************** F O R S T A T E M E N T *************************************************
|
||||
// ********************************************************************************************************************************
|
||||
//INIT
|
||||
//L1:
|
||||
// CONDITION
|
||||
// IF FALSE -> L2
|
||||
//BODY
|
||||
//INCREMENT
|
||||
//GOTO L1
|
||||
//L2: NOOP
|
||||
public void ForStatement()
|
||||
{
|
||||
long codePointerL1;
|
||||
long codePointerFalseBranch;
|
||||
long codePointerL2;
|
||||
long codePointerTerminalAddress;
|
||||
|
||||
loopStack.Push(true); // register this is a for loop
|
||||
InsertSymbols(expressionSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(Scanner.ScanSymbols.for1);
|
||||
Expect(Scanner.ScanSymbols.leftparen1);
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(directiveSymbols);
|
||||
if (IsInError) { loopStack.Pop(); return; }
|
||||
DoInitialization(); // Do initialization. I=1
|
||||
codePointerL1 = CodePointer(); // execution target codePointerL1
|
||||
DoForCondition(); // e.g., I < 10 // emit the for condition
|
||||
codePointerFalseBranch = CodePointer(); // get the location in the stream for the defaddr2 that follows
|
||||
Emit(Parser.ParserSymbols.defaddr2, 0L); // emit defaddr2 (jump if false) with dummy address of 0L
|
||||
BeginCapture(); // start a new code emit frame
|
||||
DoForIncrement(); // emit the increment code e.g., I = I + 1
|
||||
CapturedCode code = EndCapture(); // end the capture and retrieve the emitted code
|
||||
DoForBlock(); // emit the BODY
|
||||
Emit(code); // emit the increment
|
||||
if (IsInError) { loopStack.Pop(); return; } // check error condition
|
||||
Emit(Parser.ParserSymbols.goto2, codePointerL1); // jump back to condition after the body
|
||||
codePointerL2 = CodePointer(); // get the location in the stream for the L2 exit location
|
||||
Emit(Parser.ParserSymbols.noop2); // emit a noop at the current location
|
||||
codePointerTerminalAddress = CodePointer(); // Record code pointer before seeking
|
||||
Seek(codePointerFalseBranch); // seek to the defaddr2 statement that we emitted above
|
||||
Emit(Parser.ParserSymbols.defaddr2, codePointerL2); // rewrite that statement with the correct branch address of L2 exit marker
|
||||
HandleBreak(codePointerL2); // Handle any breaks
|
||||
Seek(codePointerTerminalAddress); // seek to Terminal address in order to leave the stream at the correct location at the end of this all.
|
||||
loopStack.Pop();
|
||||
}
|
||||
|
||||
private void DoForIncrement()
|
||||
{
|
||||
InsertSymbols(new ParseSymbol(Scanner.ScanSymbols.rightparen1));
|
||||
InsertSymbols(statementSymbols);
|
||||
Expect(Scanner.ScanSymbols.semicolon1);
|
||||
Statement();
|
||||
RemoveSymbols(statementSymbols);
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.rightparen1));
|
||||
InsertSymbols(new ParseSymbol(Scanner.ScanSymbols.leftcurly1));
|
||||
Expect(Scanner.ScanSymbols.rightparen1);
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.leftcurly1));
|
||||
}
|
||||
|
||||
private void DoForBlock()
|
||||
{
|
||||
InsertSymbols(new ParseSymbol(Scanner.ScanSymbols.rightcurly1));
|
||||
InsertSymbols(statementSymbols);
|
||||
Expect(Scanner.ScanSymbols.leftcurly1); // at this point we have {
|
||||
if(IsInError)return;
|
||||
while(!SymbolIn(new ParseSymbol(Scanner.ScanSymbols.rightcurly1)) && !IsInError)
|
||||
{
|
||||
Statement();
|
||||
}
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.rightcurly1));
|
||||
Expect(Scanner.ScanSymbols.rightcurly1);
|
||||
if(IsInError)return;
|
||||
RemoveSymbols(statementSymbols);
|
||||
}
|
||||
|
||||
|
||||
private void DoForCondition()
|
||||
{
|
||||
long enterSymbolCount = SymbolCount();
|
||||
Stack<Parser.ParserSymbols> logicalOperatorStack = new Stack<Parser.ParserSymbols>();
|
||||
|
||||
while (!IsInError)
|
||||
{
|
||||
// Stop at the increment separator
|
||||
if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.semicolon1)))
|
||||
break;
|
||||
|
||||
bool inShortFunction = false;
|
||||
InsertSymbols(expressionSymbols);
|
||||
if (PeekSymbolIn(directiveSymbols)) inShortFunction = true;
|
||||
|
||||
InsertSymbols(new ParseSymbol(Scanner.ScanSymbols.semicolon1));
|
||||
InsertSymbols(logicalSymbols);
|
||||
|
||||
// Parse left-hand side expression and relation
|
||||
Expression();
|
||||
Relation();
|
||||
|
||||
InsertSymbols(relationSymbols);
|
||||
SyntaxCheck();
|
||||
if (IsInError) return;
|
||||
|
||||
RemoveSymbols(relationSymbols);
|
||||
RemoveSymbols(logicalSymbols);
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.semicolon1));
|
||||
|
||||
// Handle short functions or logical chaining
|
||||
if (inShortFunction || SymbolIn(logicalSymbols))
|
||||
{
|
||||
if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.oror1)))
|
||||
{
|
||||
logicalOperatorStack.Push(Parser.ParserSymbols.oror2);
|
||||
InsertSymbols(expressionSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(currentSymbolType);
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(expressionSymbols); // yes, twice
|
||||
RemoveSymbols(directiveSymbols);
|
||||
continue;
|
||||
}
|
||||
else if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.andand1)))
|
||||
{
|
||||
logicalOperatorStack.Push(Parser.ParserSymbols.andand2);
|
||||
InsertSymbols(expressionSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(currentSymbolType);
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(expressionSymbols); // yes, twice
|
||||
RemoveSymbols(directiveSymbols);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop if next symbol is semicolon (increment)
|
||||
if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.semicolon1)))
|
||||
{
|
||||
RemoveSymbols(expressionSymbols);
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse relational operator
|
||||
ParseSymbol relationSymbol = new ParseSymbol(currentSymbolType);
|
||||
InsertSymbols(new ParseSymbol(Scanner.ScanSymbols.leftcurly1));
|
||||
InsertSymbols(logicalSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(currentSymbolType);
|
||||
if (IsInError) return;
|
||||
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(directiveSymbols);
|
||||
|
||||
if (!inShortFunction)
|
||||
{
|
||||
InsertSymbols(new ParseSymbol(Scanner.ScanSymbols.rightparen1));
|
||||
|
||||
if (SymbolIn(directiveSymbols))
|
||||
{
|
||||
InsertSymbols(relationSymbols);
|
||||
Directive();
|
||||
Relation();
|
||||
RemoveSymbols(relationSymbols);
|
||||
}
|
||||
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.rightparen1));
|
||||
if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.rightparen1)))
|
||||
Expect(Scanner.ScanSymbols.rightparen1);
|
||||
|
||||
EmitRelation(relationSymbol);
|
||||
}
|
||||
|
||||
// Emit any logical operators in stack
|
||||
if (logicalOperatorStack.Count != 0)
|
||||
Emit(logicalOperatorStack.Pop());
|
||||
|
||||
// Check for trailing logical operators
|
||||
if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.oror1)))
|
||||
{
|
||||
logicalOperatorStack.Push(Parser.ParserSymbols.oror2);
|
||||
InsertSymbols(expressionSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(currentSymbolType);
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(directiveSymbols);
|
||||
}
|
||||
else if (SymbolIn(new ParseSymbol(Scanner.ScanSymbols.andand1)))
|
||||
{
|
||||
logicalOperatorStack.Push(Parser.ParserSymbols.andand2);
|
||||
InsertSymbols(expressionSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(currentSymbolType);
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(directiveSymbols);
|
||||
}
|
||||
|
||||
RemoveSymbols(logicalSymbols);
|
||||
RemoveSymbols(new ParseSymbol(Scanner.ScanSymbols.leftcurly1));
|
||||
RemoveSymbols(expressionSymbols);
|
||||
|
||||
if (!SymbolIn(expressionSymbols) && !SymbolIn(directiveSymbols))
|
||||
break;
|
||||
}
|
||||
|
||||
// Emit remaining logical operators
|
||||
while (logicalOperatorStack.Count > 0)
|
||||
Emit(logicalOperatorStack.Pop());
|
||||
|
||||
// Check symbol stack consistency
|
||||
long exitSymbolCount = SymbolCount();
|
||||
if (enterSymbolCount != exitSymbolCount)
|
||||
throw new InvalidOperationException("Symbol counts do not match");
|
||||
}
|
||||
|
||||
private void EmitRelation(ParseSymbol relationSymbol)
|
||||
{
|
||||
if (relationSymbol.Equals(new ParseSymbol(Scanner.ScanSymbols.notequal1)))
|
||||
{
|
||||
Emit(Parser.ParserSymbols.notequal2);
|
||||
}
|
||||
else if (relationSymbol.Equals(new ParseSymbol(Scanner.ScanSymbols.equalequal1)))
|
||||
{
|
||||
Emit(Parser.ParserSymbols.equalequal2);
|
||||
}
|
||||
else if (relationSymbol.Equals(new ParseSymbol(Scanner.ScanSymbols.less1)))
|
||||
{
|
||||
Emit(Parser.ParserSymbols.less2);
|
||||
}
|
||||
else if (relationSymbol.Equals(new ParseSymbol(Scanner.ScanSymbols.lessequal1)))
|
||||
{
|
||||
Emit(Parser.ParserSymbols.lessequal2);
|
||||
}
|
||||
else if (relationSymbol.Equals(new ParseSymbol(Scanner.ScanSymbols.greater1)))
|
||||
{
|
||||
Emit(Parser.ParserSymbols.greater2);
|
||||
}
|
||||
else if (relationSymbol.Equals(new ParseSymbol(Scanner.ScanSymbols.greaterequal1)))
|
||||
{
|
||||
Emit(Parser.ParserSymbols.greaterequal2);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoInitialization()
|
||||
{
|
||||
// for (; ... ) → empty initialization
|
||||
if(SymbolIn(new ParseSymbol(Scanner.ScanSymbols.semicolon1)))return;
|
||||
// Reuse your normal assignment parser
|
||||
Statement();
|
||||
}
|
||||
|
||||
private void DoIncrement()
|
||||
{
|
||||
if(SymbolIn(new ParseSymbol(Scanner.ScanSymbols.rightparen1)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Expression();
|
||||
}
|
||||
// ********************************************************************************************************************************
|
||||
// ************************************************** W H I L E S T A T E M E N T **********************************************
|
||||
// ********************************************************************************************************************************
|
||||
/// <summary>
|
||||
/// WhileStatement Parses WhileStatement.
|
||||
///WHILE
|
||||
@@ -221,36 +492,42 @@ namespace Axiom.Interpreter
|
||||
long codePointerL2;
|
||||
long codePointerTerminalAddress;
|
||||
|
||||
whileStack.Push(true); // Register that we are processing a while loop
|
||||
loopStack.Push(true); // Register that we are processing a while loop
|
||||
InsertSymbols(expressionSymbols);
|
||||
InsertSymbols(directiveSymbols);
|
||||
Expect(Scanner.ScanSymbols.while1);
|
||||
Expect(Scanner.ScanSymbols.leftparen1);
|
||||
RemoveSymbols(expressionSymbols);
|
||||
RemoveSymbols(directiveSymbols);
|
||||
if (IsInError){whileStack.Pop(); return;}
|
||||
if (IsInError){loopStack.Pop(); return;}
|
||||
codePointerL1 = CodePointer(); // L1:
|
||||
DoBForWhile(); // B
|
||||
if(IsInError){whileStack.Pop(); return;}
|
||||
if(IsInError){loopStack.Pop(); return;}
|
||||
codePointerFalseInstructionAddress = CodePointer(); // Record the location of the DEFADDR2 instruction.
|
||||
Emit(Parser.ParserSymbols.defaddr2,0L); // Write DEFADDR2,0L. This will be jump to condition:false
|
||||
DoSForWhile(); // S
|
||||
if(IsInError){whileStack.Pop(); return;}
|
||||
if(IsInError){loopStack.Pop(); return;}
|
||||
Emit(Parser.ParserSymbols.goto2,codePointerL1); // Goto(L1)
|
||||
codePointerL2=CodePointer(); // L2:
|
||||
Emit(Parser.ParserSymbols.noop2); // Don't write any instructions past this point
|
||||
codePointerTerminalAddress=CodePointer(); // Record code pointer before seeking
|
||||
Seek(codePointerFalseInstructionAddress); // Seek to DEFADDR2 instruction
|
||||
Emit(Parser.ParserSymbols.defaddr2,codePointerL2); // Write DEFADDR2, L2
|
||||
HandleBreak(codePointerL2); // If there was a break statement then handle to jump condition
|
||||
HandleBreak(codePointerL2); // If there was a break statement then handle the jump to condition
|
||||
Seek(codePointerTerminalAddress);
|
||||
loopStack.Pop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the handling for break statements in while loops
|
||||
/// For the while statement there will be a DEFADDR, L2 just prior to a NOOP
|
||||
/// </summary>
|
||||
/// <param name="codePointerL2"></param>
|
||||
public void HandleBreak(long codePointerL2)
|
||||
{
|
||||
if(0==breakStack.Count)return;
|
||||
Seek(breakStack.Pop());
|
||||
Emit(Parser.ParserSymbols.goto2,codePointerL2);
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// B Section for While.
|
||||
@@ -1499,6 +1776,12 @@ namespace Axiom.Interpreter
|
||||
else SyntaxError(symbol);
|
||||
SyntaxCheck();
|
||||
}
|
||||
|
||||
public long SymbolCount()
|
||||
{
|
||||
return parseSymbols.Count;
|
||||
}
|
||||
|
||||
public void InsertSymbols(ParseSymbols groupSymbols)
|
||||
{
|
||||
parseSymbols.InsertSymbols(groupSymbols);
|
||||
@@ -1600,6 +1883,7 @@ namespace Axiom.Interpreter
|
||||
statementSymbols.Add(new ParseSymbol(Scanner.ScanSymbols.literal1));
|
||||
statementSymbols.Add(new ParseSymbol(Scanner.ScanSymbols.if1));
|
||||
statementSymbols.Add(new ParseSymbol(Scanner.ScanSymbols.while1));
|
||||
statementSymbols.Add(new ParseSymbol(Scanner.ScanSymbols.for1));
|
||||
statementSymbols.Add(new ParseSymbol(Scanner.ScanSymbols.declare1));
|
||||
statementSymbols.Add(new ParseSymbol(Scanner.ScanSymbols.break1));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user