diff --git a/Axiom.Core/Axiom.Core.csproj b/Axiom.Core/Axiom.Core.csproj
index f75d3d1..3b7d731 100644
--- a/Axiom.Core/Axiom.Core.csproj
+++ b/Axiom.Core/Axiom.Core.csproj
@@ -64,6 +64,7 @@
+
diff --git a/Axiom.Core/Interpreter/Assembler.cs b/Axiom.Core/Interpreter/Assembler.cs
index 989d9de..4030c40 100644
--- a/Axiom.Core/Interpreter/Assembler.cs
+++ b/Axiom.Core/Interpreter/Assembler.cs
@@ -612,6 +612,7 @@ namespace Axiom.Interpreter
lastMessage=exception.ToString();
}
}
+
private void Negate()
{
try
diff --git a/Axiom.Core/Interpreter/CapturedCode.cs b/Axiom.Core/Interpreter/CapturedCode.cs
new file mode 100644
index 0000000..eb26fab
--- /dev/null
+++ b/Axiom.Core/Interpreter/CapturedCode.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Axiom.Interpreter
+{
+ public class CapturedCode
+ {
+ private readonly byte[] codeBytes;
+
+ public CapturedCode(byte[] codeBytes)
+ {
+ this.codeBytes = codeBytes ?? throw new ArgumentNullException(nameof(codeBytes));
+ }
+ public int Length => codeBytes.Length;
+
+ public byte[] Bytes => (byte[])codeBytes;
+ }
+}
diff --git a/Axiom.Core/Interpreter/CodeRunner.cs b/Axiom.Core/Interpreter/CodeRunner.cs
index 00f1d05..a043e0c 100644
--- a/Axiom.Core/Interpreter/CodeRunner.cs
+++ b/Axiom.Core/Interpreter/CodeRunner.cs
@@ -29,10 +29,12 @@ namespace Axiom.Interpreter
symbolTable=new SymbolTable();
IsInError=false;
}
+
~CodeRunner()
{
Dispose(false);
}
+
public void Dispose()
{
if (!disposed)
@@ -41,6 +43,7 @@ namespace Axiom.Interpreter
GC.SuppressFinalize(this);
}
}
+
protected virtual void Dispose(bool disposing)
{
if(disposing)
@@ -53,32 +56,40 @@ namespace Axiom.Interpreter
}
disposed = true;
}
+
public int ParseSymbolsCount
{
get{return parseSymbolCount;}
}
+
public String LastMessage{ get; private set;}
+
public bool IsInError { get; private set;}
+
public bool ScanStrict
{
get{return scanStrict;}
set{scanStrict=value;}
}
+
public bool ParseStrict
{
get{return parseStrict;}
set{parseStrict=value;}
}
+
public bool Trace
{
get {return trace;}
set {trace=value;}
}
+
public bool UseCache
{
get { return useCache; }
set { useCache = value; }
}
+
public String GetValue(String name)
{
if (!symbolTable.ContainsKey(name)) return "null";
@@ -87,6 +98,7 @@ namespace Axiom.Interpreter
if (null == genericData || genericData.IsNull()) return "null";
return genericData.Get();
}
+
public T GetValue(String name)
{
if(!symbolTable.ContainsKey(name)) return default(T);
@@ -95,20 +107,24 @@ namespace Axiom.Interpreter
if(null==genericData||genericData.IsNull()) return default(T);
return genericData.Get();
}
+
public SymbolTable SymbolTable
{
get {return symbolTable;}
}
+
public void Reset()
{
if (null == symbolTable) return;
symbolTable.Reset();
}
+
public bool Execute(DataTable dataTable, int row, String expression)
{
Reset();
return ExecuteExpressionOnRow(dataTable, row, expression);
}
+
private bool ExecuteExpressionOnRow(DataTable dataTable, int row, String expression)
{
symbolTable.AddUserSymbols(dataTable); // add symbol names from the data table columns
@@ -123,6 +139,13 @@ namespace Axiom.Interpreter
}
return true;
}
+
+ ///
+ /// Execute - Executes the given expression. You can then use the helper methods.
+ /// GetValue(String), GetValue(String) to retrieve resulting variables from the symbolTable
+ ///
+ ///
+ ///
public bool Execute(String expression)
{
BinaryReader binaryReader = null;
@@ -161,7 +184,7 @@ namespace Axiom.Interpreter
logger.ErrorFormat(LastMessage);
return false;
}
- parserWriter.BaseStream.Seek(0, SeekOrigin.Begin);
+ parserWriter.BaseStream.Seek(0, SeekOrigin.Begin); // SEEK TO THE BEGINNING OF THE CODE
assemblerReader = new BinaryReader(parserWriter.BaseStream);
assembler = new Assembler(assemblerReader, symbolTable);
assembler.Debug = Trace;
@@ -196,6 +219,11 @@ namespace Axiom.Interpreter
}
}
+ ///
+ /// Disassemble - This method does not execute code. It scans, parses, and disassembles the geenrated bytecode
+ ///
+ ///
+ ///
public List Disassemble(String expression)
{
BinaryReader binaryReader = null;
@@ -210,9 +238,10 @@ namespace Axiom.Interpreter
{
IsInError=false;
LastMessage="";
+ SymbolTable localSymbolTable = new SymbolTable();
binaryReader = new BinaryReader(Utility.StreamFromString(expression));
binaryWriter = new BinaryWriter(new MemoryStream());
- Scanner scanner = new Scanner(binaryReader, binaryWriter, symbolTable);
+ Scanner scanner = new Scanner(binaryReader, binaryWriter, localSymbolTable);
scanner.Debug = Trace;
if (!scanner.Analyze())
{
@@ -224,7 +253,7 @@ namespace Axiom.Interpreter
binaryWriter.BaseStream.Seek(0, SeekOrigin.Begin);
parserReader = new BinaryReader(binaryWriter.BaseStream);
parserWriter = new BinaryWriter(new MemoryStream());
- Parser parser = new Parser(parserReader, parserWriter, symbolTable);
+ Parser parser = new Parser(parserReader, parserWriter, localSymbolTable);
parser.Debug = Trace;
parser.Parse();
parseSymbolCount=parser.ParseSymbolsCount;
@@ -237,7 +266,7 @@ namespace Axiom.Interpreter
}
parserWriter.BaseStream.Seek(0, SeekOrigin.Begin);
assemblerReader = new BinaryReader(parserWriter.BaseStream);
- assembler = new Assembler(assemblerReader, symbolTable);
+ assembler = new Assembler(assemblerReader, localSymbolTable);
assembler.Debug = Trace;
return assembler.Disassemble();
}
@@ -412,7 +441,7 @@ namespace Axiom.Interpreter
{
logger.Info("********************************************************* O U T P U T ************************************************");
List list = new List(symbolTable.Values);
- list = (from Symbol symbol in list where symbol.TypeOfSymbol.Equals(Symbol.SymbolType.UserSymbol) select symbol).ToList();
+// list = (from Symbol symbol in list where symbol.TypeOfSymbol.Equals(Symbol.SymbolType.UserSymbol) select symbol).ToList();
foreach (Symbol symbol in list)
{
logger.Info(String.Format("SYMBOL NAME:'{0}',VALUE:'{1}'", symbol.SymbolName, null == symbol.GenericData ? "" : symbol.GenericData.ToString()));
diff --git a/Axiom.Core/Interpreter/Emitter.cs b/Axiom.Core/Interpreter/Emitter.cs
index ddb7513..f119770 100644
--- a/Axiom.Core/Interpreter/Emitter.cs
+++ b/Axiom.Core/Interpreter/Emitter.cs
@@ -1,204 +1,248 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
-using log4net;
-
-// FileName : Emitter.cs
-// Author : Sean Kessler
+using MarketData;
namespace Axiom.Interpreter
{
public class Emitter
{
- private static ILog logger = LogManager.GetLogger(typeof(Emitter));
private bool emitting = true;
private int lastSymbol;
private BinaryReader inputStream;
- private BinaryWriter outputStream;
+ private BinaryWriter outputStream; // the assigned output stream
+ private BinaryWriter activeStream; // the active stream
+ private Stack writeStack = new Stack();
+ private Stack captureStack = new Stack();
+ private bool isCapturing = false;
private bool debug = true;
public Emitter(BinaryReader inputStream, BinaryWriter outputStream)
{
this.inputStream = inputStream;
this.outputStream = outputStream;
+ this.activeStream = outputStream;
}
+
public bool Debug
{
get { return debug; }
set { debug = value; }
}
+
+ public void BeginCapture()
+ {
+ writeStack.Push(activeStream);
+ activeStream = new BinaryWriter(new MemoryStream());
+ isCapturing = true;
+ }
+
+ public void EndCapture()
+ {
+ if (!isCapturing)throw new InvalidOperationException("EndCapture called without a matching BeginCapture.");
+ activeStream.Flush();
+ MemoryStream memoryStream = (MemoryStream)activeStream.BaseStream;
+ byte[] capturedBytes = memoryStream.ToArray();
+ activeStream.Close();
+ activeStream.Dispose();
+ activeStream = writeStack.Pop();
+ isCapturing = writeStack.Count > 0;
+ captureStack.Push(new CapturedCode(capturedBytes));
+ }
+
+ ///
+ /// EmitCapture - Later, for CONTINUE semantics, we can Peek() at the top of the captureStack to get the increment code without popping it.
+ ///
+ public void EmitCapture()
+ {
+ if(0==captureStack.Count)throw new InvalidOperationException("The CaptureList is empty.");
+ CapturedCode code = captureStack.Pop();
+ activeStream.Write(code.Bytes,0,code.Length);
+ }
+
public void Emit(String literalValue)
{
if (!emitting) return;
- outputStream.Write(literalValue.Length);
- outputStream.Write(literalValue);
+ activeStream.Write(literalValue.Length);
+ activeStream.Write(literalValue);
}
-// ************************************************************************
+
public void Emit(Scanner.ScanSymbols code)
{
if (!emitting) return;
- outputStream.Write((int)code);
- if(Debug)logger.Info(Scanner.SymbolToString(code));
+ activeStream.Write((int)code);
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Scanner.SymbolToString(code));
}
+
public void Emit(Scanner.ScanSymbols code,int value)
{
if (!emitting) return;
- outputStream.Write((int)code);
- outputStream.Write(value);
- if(Debug)logger.Info(Scanner.SymbolToString(code)+","+value.ToString());
+ activeStream.Write((int)code);
+ activeStream.Write(value);
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Scanner.SymbolToString(code) + "," + value.ToString());
}
+
public void Emit(Scanner.ScanSymbols code,double value)
{
if (!emitting) return;
- outputStream.Write((int)code);
- outputStream.Write(value);
- if(Debug)logger.Info(Scanner.SymbolToString(code)+","+value.ToString());
+ activeStream.Write((int)code);
+ activeStream.Write(value);
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Scanner.SymbolToString(code) + "," + value.ToString());
}
+
public void Emit(Scanner.ScanSymbols code,String value)
{
if (!emitting) return;
- outputStream.Write((int)code);
- outputStream.Write(value);
- if(Debug)logger.Info(Scanner.SymbolToString(code)+","+value.ToString());
+ activeStream.Write((int)code);
+ activeStream.Write(value);
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Scanner.SymbolToString(code) + "," + value.ToString());
}
-// **********************************************************************************************************************************************
- public long CodePointer()
- {
- return outputStream.BaseStream.Position;
+
+ public long CodePointer()
+ {
+ return activeStream.BaseStream.Position;
}
- public void Seek(long position)
- {
- outputStream.BaseStream.Seek(position, SeekOrigin.Begin);
+
+ public void Seek(long position)
+ {
+ activeStream.BaseStream.Seek(position, SeekOrigin.Begin);
}
+
public void Emit(Parser.ParserSymbols code)
{
if (!emitting) return;
- long positionBefore=outputStream.BaseStream.Position;
- outputStream.Write((int)code);
- long positionAfter=outputStream.BaseStream.Position;
- if(Debug)logger.Info(Parser.SymbolToString(code)+"["+positionBefore+","+positionAfter+"]");
-
+ long positionBefore = activeStream.BaseStream.Position;
+ activeStream.Write((int)code);
+ long positionAfter = activeStream.BaseStream.Position;
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Parser.SymbolToString(code) + "[" + positionBefore + "," + positionAfter + "]");
}
+
public void Emit(Parser.ParserSymbols code,Object value)
{
if (!emitting) return;
- long positionBefore=outputStream.BaseStream.Position;
- outputStream.Write((int)code);
+ long positionBefore = activeStream.BaseStream.Position;
+ activeStream.Write((int)code);
Type type = value.GetType();
- outputStream.Write(type.ToString());
- outputStream.Write(value.ToString());
- long positionAfter=outputStream.BaseStream.Position;
- if(Debug)logger.Info(Parser.SymbolToString(code)+","+type.ToString()+","+value.ToString()+"["+positionBefore+","+positionAfter+"]");
+ activeStream.Write(type.ToString());
+ activeStream.Write(value.ToString());
+ long positionAfter = activeStream.BaseStream.Position;
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Parser.SymbolToString(code) + "," + type.ToString() + "," + value.ToString() + "[" + positionBefore + "," + positionAfter + "]");
}
+
public void Emit(Parser.ParserSymbols code,Object value,int intValue)
{
if (!emitting) return;
- long positionBefore=outputStream.BaseStream.Position;
- outputStream.Write((int)code);
+ long positionBefore = activeStream.BaseStream.Position;
+ activeStream.Write((int)code);
Type type = value.GetType();
- outputStream.Write(type.ToString());
- outputStream.Write(value.ToString());
- outputStream.Write(intValue);
- long positionAfter=outputStream.BaseStream.Position;
- if(Debug)logger.Info(Parser.SymbolToString(code)+","+type.ToString()+","+value.ToString()+","+intValue+"["+positionBefore+","+positionAfter+"]");
+ activeStream.Write(type.ToString());
+ activeStream.Write(value.ToString());
+ activeStream.Write(intValue);
+ long positionAfter = activeStream.BaseStream.Position;
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Parser.SymbolToString(code) + "," + type.ToString() + "," + value.ToString() + "," + intValue + "[" + positionBefore + "," + positionAfter + "]");
}
+
public void Emit(Parser.ParserSymbols code,long value)
{
if (!emitting) return;
- long positionBefore=outputStream.BaseStream.Position;
- outputStream.Write((int)code);
- outputStream.Write(value);
- long positionAfter=outputStream.BaseStream.Position;
- if(Debug)logger.Info(Parser.SymbolToString(code)+","+value.ToString()+","+value.ToString()+"["+positionBefore+","+positionAfter+"]");
+ long positionBefore = activeStream.BaseStream.Position;
+ activeStream.Write((int)code);
+ activeStream.Write(value);
+ long positionAfter = activeStream.BaseStream.Position;
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Parser.SymbolToString(code) + "," + value.ToString() + "," + value.ToString() + "[" + positionBefore + "," + positionAfter + "]");
}
+
public void EmitAsNull(Parser.ParserSymbols code)
{
if (!emitting) return;
- long positionBefore=outputStream.BaseStream.Position;
- outputStream.Write((int)code);
- Type type = typeof(System.Nullable); //value.GetType();
- outputStream.Write(type.ToString());
- outputStream.Write("null".ToString());
- long positionAfter=outputStream.BaseStream.Position;
- if(Debug)logger.Info(Parser.SymbolToString(code)+","+type.ToString()+","+"null".ToString()+"["+positionBefore+","+positionAfter+"]");
+ long positionBefore = activeStream.BaseStream.Position;
+ activeStream.Write((int)code);
+ Type type = typeof(System.Nullable);
+ activeStream.Write(type.ToString());
+ activeStream.Write("null".ToString());
+ long positionAfter = activeStream.BaseStream.Position;
+ if (Debug) MDTrace.WriteLine(LogLevel.DEBUG, Parser.SymbolToString(code) + "," + type.ToString() + "," + "null" + "[" + positionBefore + "," + positionAfter + "]");
}
-// ************************************************************************
- public void Emit(int code, int op)
+
+ public void Emit(int code,int op)
{
if (!emitting) return;
- outputStream.Write(code);
- outputStream.Write(op);
+ activeStream.Write(code);
+ activeStream.Write(op);
}
+
public void Emit(int identifier)
{
if (!emitting) return;
- outputStream.Write(identifier);
+ activeStream.Write(identifier);
}
+
public void Emit(byte value)
{
if (!emitting) return;
- outputStream.Write(value);
+ activeStream.Write(value);
+ }
+
+ public int Peek(ref int value)
+ {
+ value = inputStream.PeekChar();
+ return value;
+ }
+
+ public int Peek()
+ {
+ int value = inputStream.PeekChar();
+ return value;
+ }
+
+ public int PeekIgnore(ref int value,int[] ignoreChars)
+ {
+ long streamPosition = inputStream.BaseStream.Position;
+ while (true)
+ {
+ int readValue = (int)inputStream.ReadChar();
+ value = readValue;
+ if (!ignoreChars.Any(x => x.Equals(readValue))) break;
+ }
+ inputStream.BaseStream.Seek(streamPosition, SeekOrigin.Begin);
+ return value;
}
- public int Peek(ref int value)
- {
- value = inputStream.PeekChar();
- return value;
- }
- public int Peek()
- {
- int value = inputStream.PeekChar();
- return value;
- }
- public int PeekIgnore(ref int value,int[] ignoreChars)
- {
- long streamPosition=inputStream.BaseStream.Position;
- while(true)
- {
- int readValue;
- readValue=(int)inputStream.ReadChar();
- value=readValue;
- if(!ignoreChars.Any(x=>x.Equals(readValue)))break;
- }
- inputStream.BaseStream.Seek(streamPosition,SeekOrigin.Begin);
- return value;
- }
public int Read()
{
lastSymbol = inputStream.Read();
return lastSymbol;
}
+
public int Read(ref String literal)
{
- literal=inputStream.ReadString();
+ literal = inputStream.ReadString();
return 0;
}
+
public int Read(ref byte value)
{
try { value = inputStream.ReadByte(); return 0; }
catch (EndOfStreamException) { return 0xFFFF; }
}
+
public int Read(ref int value)
{
try { value = inputStream.ReadInt32(); return 0; }
catch (EndOfStreamException) { return 0xFFFF; }
-
}
+
public int Read(ref double value)
{
try { value = inputStream.ReadDouble(); return 0; }
catch (EndOfStreamException) { return 0xFFFF; }
}
+
public bool Emitting
{
- get
- {
- return emitting;
- }
- set
- {
- emitting = value;
- }
+ get { return emitting; }
+ set { emitting = value; }
}
}
-}
+}
\ No newline at end of file
diff --git a/Axiom.Core/Interpreter/Parser.cs b/Axiom.Core/Interpreter/Parser.cs
index 4e82b2b..2af96ad 100644
--- a/Axiom.Core/Interpreter/Parser.cs
+++ b/Axiom.Core/Interpreter/Parser.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.IO;
+using System.Runtime.Remoting.Messaging;
// 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 breakStack = new Stack(); // when we encounter a break statement we need to record the address of the code pointer
- private Stack whileStack = new Stack(); // when we encounter a while statement we need to record the event so that we can validate any break statements
+ private Stack loopStack = new Stack(); // 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
+ EndCapture(); // end the capture and retrieve the emitted code
+ DoForBlock(); // emit the BODY
+ EmitCapture(); // emit the code block we captured above between BeginCapture and EndCapture
+ 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 logicalOperatorStack = new Stack();
+
+ 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 **********************************************
+// ********************************************************************************************************************************
///
/// 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();
}
+
+ ///
+ /// 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
+ ///
+ ///
public void HandleBreak(long codePointerL2)
{
if(0==breakStack.Count)return;
Seek(breakStack.Pop());
Emit(Parser.ParserSymbols.goto2,codePointerL2);
-
}
///
/// 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));
}
diff --git a/Axiom.Core/Interpreter/Scanner.cs b/Axiom.Core/Interpreter/Scanner.cs
index d3bc546..5c7cd2a 100644
--- a/Axiom.Core/Interpreter/Scanner.cs
+++ b/Axiom.Core/Interpreter/Scanner.cs
@@ -9,7 +9,11 @@ namespace Axiom.Interpreter
{
public class Scanner : Emitter
{
- public enum ScanSymbols { unknown1, directive_clear_modified1,declare1, null1, isnull1, convert1, getprice1, substring1, in1, like1, trim1, upper1, lower1, assign1, if1, while1, then1,else1,goto1,equal1,equalequal1,less1,lessequal1,greater1,greaterequal1, notequal1,variable1, asterisk1, apostrophe1, comma1, label1, literal1, leftcurly1, rightcurly1, leftbracket1, rightbracket1, numeral1, char1, divide1, plus1, minus1, leftparen1, rightparen1, newline1, semicolon1,endtext1, andand1, oror1, abs1, not1, pow1, sqrt1, break1, end1 };
+ public enum ScanSymbols { unknown1, directive_clear_modified1,declare1, null1, isnull1, convert1,
+ getprice1, substring1, in1, like1, trim1, upper1, lower1, assign1, if1, while1, for1, then1, else1, goto1,
+ equal1, equalequal1, less1, lessequal1, greater1, greaterequal1, notequal1, variable1, asterisk1, apostrophe1,
+ comma1, label1, literal1, leftcurly1, rightcurly1, leftbracket1, rightbracket1, numeral1, char1, divide1, plus1,
+ minus1, leftparen1, rightparen1, newline1, semicolon1,endtext1, andand1, oror1, abs1, not1, pow1, sqrt1, break1, end1 };
private enum WhiteSpace{spacechar=32,tabchar=9};
private int character;
private StringBuilder word;
@@ -409,6 +413,8 @@ namespace Axiom.Interpreter
return "if";
case Scanner.ScanSymbols.while1 :
return "while";
+ case Scanner.ScanSymbols.for1 :
+ return "for";
case Scanner.ScanSymbols.then1 :
return "then";
case Scanner.ScanSymbols.else1 :
@@ -523,6 +529,8 @@ namespace Axiom.Interpreter
return "if1";
case Scanner.ScanSymbols.while1 :
return "while1";
+ case Scanner.ScanSymbols.for1 :
+ return "for1";
case Scanner.ScanSymbols.then1 :
return "then1";
case Scanner.ScanSymbols.else1 :
diff --git a/Axiom.Core/Interpreter/SymbolTable.cs b/Axiom.Core/Interpreter/SymbolTable.cs
index 0855668..6cf0320 100644
--- a/Axiom.Core/Interpreter/SymbolTable.cs
+++ b/Axiom.Core/Interpreter/SymbolTable.cs
@@ -140,6 +140,7 @@ namespace Axiom.Interpreter
Add("if",new Symbol("if",Scanner.ScanSymbols.if1,Symbol.SymbolType.KeywordSymbol));
Add("break",new Symbol("break",Scanner.ScanSymbols.break1,Symbol.SymbolType.KeywordSymbol));
Add("while",new Symbol("while",Scanner.ScanSymbols.while1,Symbol.SymbolType.KeywordSymbol));
+ Add("for",new Symbol("for",Scanner.ScanSymbols.for1,Symbol.SymbolType.KeywordSymbol));
Add("then", new Symbol("then", Scanner.ScanSymbols.then1, Symbol.SymbolType.KeywordSymbol));
Add("else", new Symbol("else", Scanner.ScanSymbols.else1, Symbol.SymbolType.KeywordSymbol));
Add("and", new Symbol("and", Scanner.ScanSymbols.andand1, Symbol.SymbolType.KeywordSymbol));
diff --git a/AxiomConsole/App.config b/AxiomConsole/App.config
index 8d23437..ecdcf8a 100644
--- a/AxiomConsole/App.config
+++ b/AxiomConsole/App.config
@@ -1,6 +1,6 @@
-
+
diff --git a/AxiomConsole/AxiomConsole.csproj b/AxiomConsole/AxiomConsole.csproj
index b557efe..3ac3c07 100644
--- a/AxiomConsole/AxiomConsole.csproj
+++ b/AxiomConsole/AxiomConsole.csproj
@@ -9,7 +9,7 @@
Properties
AxiomConsole
AxiomConsole
- v4.6.2
+ v4.7.2
512
diff --git a/AxiomConsole/Program.cs b/AxiomConsole/Program.cs
index 805b663..f1b227b 100644
--- a/AxiomConsole/Program.cs
+++ b/AxiomConsole/Program.cs
@@ -22,52 +22,61 @@ namespace AxiomConsole
// IF(A==1)THEN BREAK;
// A=A+1;
// }";
- String expression=@"
- A=1;
- B=1;
- C=1;
- D=1;
- WHILE(A<10)
- {
- WHILE(B<10)
+ //String expression = @"
+ // J=1;
+ // FOR(I=1;I<10;I=I+1)
+ // {
+ // J=J+10;
+ // break;
+ // }
+ // ";
+
+ //String expression = @"
+ // J=1;
+ // FOR(I=1;I<10;I=I+1)
+ // {
+ // J=J+10;
+ // }
+ // ";
+
+ String expression = @"
+ DECLARE A,J,TOTAL;
+ A=1;
+ J=1;
+ TOTAL=0;
+ FOR(A=1;A<=10;A=A+1)
{
- WHILE(C<10)
+ FOR(J=1;J<=10;J=J+1)
{
- WHILE(D<10)
- {
- A=A+1;
- B=B+1;
- C=C+1;
- D=D+1;
- IF(D==10)THEN BREAK;
- BREAK;
- }
BREAK;
+ TOTAL=TOTAL+1
}
- BREAK;
}
- BREAK;
- }";
+ ";
+
+
CodeRunner codeRunner = new CodeRunner();
+ codeRunner.Trace=true;
//if (!codeRunner.Execute(expression))
//{
// Console.WriteLine("CodeRunner Failed with {0}", codeRunner.LastMessage);
// Console.Read();
//}
- List disassembly=codeRunner.Disassemble(expression);
- if(codeRunner.IsInError)
- {
- Console.WriteLine("CodeRunner Failed with {0}",codeRunner.LastMessage);
- }
- else
- {
- Console.WriteLine(expression);
- foreach(String line in disassembly)
- {
- Console.WriteLine(line);
- }
- }
+
+ List disassembly = codeRunner.Disassemble(expression);
+ if (codeRunner.IsInError)
+ {
+ Console.WriteLine("CodeRunner Failed with {0}", codeRunner.LastMessage);
+ } else
+ {
+ Console.WriteLine(expression);
+ foreach (String line in disassembly)
+ {
+ Console.WriteLine(line);
+ }
+ }
+
Console.Read();
}
}
diff --git a/AxiomUnitTestProject/AssemblerTests.cs b/AxiomUnitTestProject/AssemblerTests.cs
index 84422b9..1b3749c 100644
--- a/AxiomUnitTestProject/AssemblerTests.cs
+++ b/AxiomUnitTestProject/AssemblerTests.cs
@@ -176,6 +176,71 @@ namespace AxiomUnitTestProject
Assert.IsTrue(codeRunner.GetValue("B").Equals(5));
}
+ [TestMethod]
+ public void ForStatementVariant3()
+ {
+ String expression=@"
+ DECLARE A,J,TOTAL;
+ A=1;
+ J=1;
+ TOTAL=0;
+ FOR(A=1;A<=10;A=A+1)
+ {
+ FOR(J=1;J<=10;J=J+1)
+ {
+ BREAK;
+ TOTAL=TOTAL+1
+ }
+ }
+ ";
+ CodeRunner codeRunner = new CodeRunner();
+ Assert.IsTrue(codeRunner.Execute(expression),codeRunner.LastMessage);
+ Assert.IsTrue(codeRunner.GetValue("J").Equals(1));
+ Assert.IsTrue(codeRunner.GetValue("A").Equals(11));
+ Assert.IsTrue(codeRunner.GetValue("TOTAL").Equals(0));
+ }
+
+ [TestMethod]
+ public void ForStatementVariant2()
+ {
+ String expression=@"
+ DECLARE A,J,TOTAL;
+ A=1;
+ J=1;
+ TOTAL=0;
+ FOR(A=1;A<=10;A=A+1)
+ {
+ FOR(J=1;J<=10;J=J+1)
+ {
+ TOTAL=TOTAL+1;
+ }
+ }
+ ";
+ CodeRunner codeRunner = new CodeRunner();
+ Assert.IsTrue(codeRunner.Execute(expression),codeRunner.LastMessage);
+ Assert.IsTrue(codeRunner.GetValue("J").Equals(11));
+ Assert.IsTrue(codeRunner.GetValue("A").Equals(11));
+ Assert.IsTrue(codeRunner.GetValue("TOTAL").Equals(100));
+ }
+
+ [TestMethod]
+ public void ForStatementVariant1()
+ {
+ String expression=@"
+ DECLARE A,J;
+ A=1;
+ J=1;
+ FOR(A=1;A<10;A=A+1)
+ {
+ J=J+1;
+ }
+ ";
+ CodeRunner codeRunner = new CodeRunner();
+ Assert.IsTrue(codeRunner.Execute(expression),codeRunner.LastMessage);
+ Assert.IsTrue(codeRunner.GetValue("J").Equals(10));
+ Assert.IsTrue(codeRunner.GetValue("A").Equals(10));
+ }
+
[TestMethod]
public void WhileStatementVariant4()
{