Files
Axiom/Axiom.Core/Interpreter/Scanner.cs
2026-03-19 16:23:20 -04:00

634 lines
20 KiB
C#

using System;
using System.Text;
using System.IO;
// FileName : ParseSymbols.cs
// Author : Sean Kessler
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, 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;
private SymbolTable symbolTable;
public Scanner(BinaryReader binaryReader, BinaryWriter binaryWriter,SymbolTable symbolTable)
: base(binaryReader, binaryWriter)
{
this.symbolTable = symbolTable;
}
public bool Analyze()
{
if(!ReadCh())return false;
while ((int)character != -1 && character != 0x001A)
{
SkipSeparators();
if(-1==(int)character)break;
if (0xFFFF == character || 0x001A == character) break;
if (IsDigit(character) || '.'.Equals((char)character)) ScanNumeral();
else if ('\r' == character) ScanNewLine();
else if (';' == character) { Emit(ScanSymbols.semicolon1); ReadCh(); }
else if (',' == character) { Emit(ScanSymbols.comma1); ReadCh(); }
else if ('[' == character) { Emit(ScanSymbols.leftbracket1); ReadCh(); }
else if (']' == character) { Emit(ScanSymbols.rightbracket1); ReadCh(); }
else if ('*' == character) { Emit(ScanSymbols.asterisk1); ReadCh(); }
else if ('/' == character) { ScanDivide(); }
else if ('+' == character) { Emit(ScanSymbols.plus1); ReadCh(); }
else if ('-' == character) { Emit(ScanSymbols.minus1); ReadCh(); }
else if ('(' == character) { Emit(ScanSymbols.leftparen1); ReadCh(); }
else if (')' == character) { Emit(ScanSymbols.rightparen1); ReadCh(); }
else if ('!' == character) { Emit(ScanSymbols.not1); ReadCh(); }
else if ('{' == character) { Emit(ScanSymbols.leftcurly1); ReadCh(); }
else if ('}' == character) { Emit(ScanSymbols.rightcurly1); ReadCh(); }
else if ('\'' == character) ScanLiteral();
else if (';' == character) ScanComment();
else if ('=' == character) ScanEqual();
else if ('<' == character) ScanLess();
else if ('>' == character) ScanGreater();
else if ('&' == character) ScanAnd();
else if ('|' == character) ScanOr();
else if (IsAlpha(character))
{
if (!ScanWord()) return false;
}
else if ('#' == character)
{
if (!ScanDirective()) return false;
}
else
{
ScanUnknown();
return false;
}
}
Emit(Scanner.ScanSymbols.endtext1);
return true;
}
public bool ReadCh()
{
try
{
character = Read();
if (-1 == character) return false;
return true;
}
catch(Exception)
{
character = -1;
return false;
}
}
public void ScanDivide()
{
Emit(ScanSymbols.divide1);
ReadCh();
}
public bool PeekCh(ref char ch)
{
try
{
int character=Peek();
if(-1==character)return false;
ch=(Char)character;
return true;
}
catch(Exception)
{
return false;
}
}
public bool ScanDirective()
{
char nextChar='\0';
if(!PeekCh(ref nextChar))return false;
if(!nextChar.Equals('#'))return ScanWord();
while (-1!=character && 0x0D != character && 0xFFFF != character)ReadCh(); // if we have ## then take the line as a comment
return true;
}
public bool ScanWord()
{
StringBuilder sb = new StringBuilder();
while (-1!=character && 0x0D != character && !IsKeySymbol() && 0xFFFF != character && (int)WhiteSpace.spacechar!=character && (int)WhiteSpace.tabchar != character)
{
sb.Append((char)character);
ReadCh();
}
if (0 == sb.Length) return true;
String symbolName = sb.ToString();
if (':'.Equals((char)character))
{
Emit(ScanSymbols.label1);
Emit(symbolName);
ReadCh();
}
else if(symbolTable.ContainsKey(symbolName))
{
Symbol symbol = symbolTable[symbolName];
if (Symbol.SymbolType.FunctionSymbol.Equals(symbol.TypeOfSymbol)) Emit(symbol.Identifier);
else if(Symbol.SymbolType.KeywordSymbol.Equals(symbol.TypeOfSymbol)) Emit(symbol.Identifier);
else if(Symbol.SymbolType.DirectiveSymbol.Equals(symbol.TypeOfSymbol)) Emit(symbol.Identifier);
else Emit(ScanSymbols.variable1, symbol.SymbolName);
}
else if(symbolTable.ContainsKey(symbolName.ToLower()))
{
symbolName = symbolName.ToLower();
Symbol symbol = symbolTable[symbolName];
if (Symbol.SymbolType.FunctionSymbol.Equals(symbol.TypeOfSymbol)) Emit(symbol.Identifier);
else if(Symbol.SymbolType.KeywordSymbol.Equals(symbol.TypeOfSymbol)) Emit(symbol.Identifier);
else Emit(ScanSymbols.variable1, symbol.SymbolName);
}
else
{
Emit(ScanSymbols.variable1, symbolName);
}
return true;
}
public bool ScanNumeral()
{
int[] chBuffer = new int[128];
int chIndex = 0;
while (0xFFFF != character && (IsDigit(character) || IsInHex(character) || '.'.Equals((char)character)))
{
if (chIndex >= chBuffer.Length) return false;
chBuffer[chIndex++] = character;
ReadCh();
}
if (character == 69) Exponent(chBuffer, chIndex);
else if ('h' == character || 'H' == character) { Hex(chBuffer, chIndex); ReadCh(); }
else if ('b' == character || 'B' == character) { Binary(chBuffer, chIndex); ReadCh(); }
else if (chIndex > 0 && ('b' == chBuffer[chIndex - 1] || 'B' == chBuffer[chIndex - 1])) Binary(chBuffer, chIndex - 1);
else Decimal(chBuffer, chIndex);
return true;
}
public void Exponent(int[] chBuffer, int chIndex)
{
chBuffer[chIndex++] = character;
ReadCh();
while (0xFFFF != character && (character == 43 || character == 45 || IsDigit(character)))
{
if (chIndex >= chBuffer.Length) return;
chBuffer[chIndex++] = character;
ReadCh();
}
Decimal(chBuffer, chIndex);
}
public void Binary(int[] chBuffer,int chIndex)
{
int value=0;
int multiplier=1;
for(--chIndex;chIndex>=0;chIndex--)
{
switch(chBuffer[chIndex])
{
case '0' : break;
case '1' : {value+=multiplier;break;}
default : {Emit(ScanSymbols.unknown1);return;}
}
multiplier*=2;
}
Emit(ScanSymbols.numeral1,value);
}
public void Decimal(int[] chBuffer,int chIndex)
{
StringBuilder sb = new StringBuilder();
for (int index = 0; index < chBuffer.Length; index++) sb.Append((char)chBuffer[index]);
double value = double.Parse(sb.ToString());
Emit(ScanSymbols.numeral1,value);
}
public bool IsInHex(int character)
{
if ('A'.Equals(character) || 'B'.Equals(character) || 'C'.Equals(character) || 'D'.Equals(character) || 'E'.Equals(character) || 'F'.Equals(character) ||
'a'.Equals(character) || 'b'.Equals(character) || 'c'.Equals(character) || 'd'.Equals(character) || 'e'.Equals(character) || 'f'.Equals(character)) return true;
return false;
}
void Hex(int[] chBuffer, int chIndex)
{
int value=0;
int multiplier=1;
for(--chIndex;chIndex>=0;chIndex--)
{
switch(chBuffer[chIndex])
{
case '0' : break;
case '1' : {value+=multiplier;break;}
case '2' : {value+=multiplier*2;break;}
case '3' : {value+=multiplier*3;break;}
case '4' : {value+=multiplier*4;break;}
case '5' : {value+=multiplier*5;break;}
case '6' : {value+=multiplier*6;break;}
case '7' : {value+=multiplier*7;break;}
case '8' : {value+=multiplier*8;break;}
case '9' : {value+=multiplier*9;break;}
case 'a' :
case 'A' : {value+=multiplier*10;break;}
case 'b' :
case 'B' : {value+=multiplier*11;break;}
case 'c' :
case 'C' : {value+=multiplier*12;break;}
case 'd' :
case 'D' : {value+=multiplier*13;break;}
case 'e' :
case 'E' : {value+=multiplier*14;break;}
case 'f' :
case 'F' : {value+=multiplier*15;break;}
default : {Emit(ScanSymbols.unknown1);return;}
}
multiplier*=16;
}
Emit(ScanSymbols.numeral1,value);
}
public void SkipSeparators()
{
while (character.Equals((int)WhiteSpace.spacechar) || character.Equals((int)WhiteSpace.tabchar)) ReadCh();
}
public void ScanNewLine()
{
Emit(ScanSymbols.newline1);
ReadCh();
while (character.Equals('\n') || character.Equals('\n')) ReadCh();
}
public void ScanAnd()
{
int character=0;
Peek(ref character);
if ('&'.Equals((char)character))
{
Emit(ScanSymbols.andand1);
ReadCh();
ReadCh();
}
else
{
Emit(ScanSymbols.unknown1);
ReadCh();
}
}
public void ScanOr()
{
int character=0;
Peek(ref character);
if ('|'.Equals((char)character))
{
Emit(ScanSymbols.oror1);
ReadCh();
ReadCh();
}
else
{
Emit(ScanSymbols.unknown1);
ReadCh();
}
}
public void ScanEqual()
{
int character=0;
Peek(ref character);
if ('='.Equals((char)character))
{
Emit(ScanSymbols.equalequal1);
ReadCh();
ReadCh();
}
else
{
Emit(ScanSymbols.equal1);
ReadCh();
}
}
public void ScanLess()
{
int character=0;
Peek(ref character);
if ('='.Equals((char)character))
{
Emit(ScanSymbols.lessequal1);
ReadCh();
ReadCh();
}
else if ('>'.Equals((char)character))
{
Emit(ScanSymbols.notequal1);
ReadCh();
ReadCh();
}
else
{
Emit(ScanSymbols.less1);
ReadCh();
}
}
public void ScanGreater()
{
int character=0;
Peek(ref character);
if ('='.Equals((char)character))
{
Emit(ScanSymbols.greaterequal1);
ReadCh();
ReadCh();
}
else
{
Emit(ScanSymbols.greater1);
ReadCh();
}
}
public void ScanComment()
{
ReadCh();
while(!character.Equals('\r')&&!character.Equals(0xFFFF))ReadCh();
}
public bool IsAlpha(int character)
{
return Char.IsLetter((char)character);
}
public bool IsDigit(int character)
{
return Char.IsDigit((char)character);
}
public bool IsKeySymbol()
{
return ('}'==character||'{'==character||'<'==character||'>'==character||';'==character || ' ' == character || ',' == character || '[' == character || ']' == character || ':' == character || '*' == character || '/' == character || '+' == character || '-' == character || '(' == character || ')' == character ||'='==character);
}
public void ScanLiteral()
{
int character;
word = new StringBuilder();
ReadCh();
character = this.character;
if (character == '\'')
{
Emit(ScanSymbols.literal1,word.ToString());
ReadCh();
return;
}
while (-1!=character && 0xFFFF != this.character && 0x0D != this.character)
{
if ('\'' == this.character)
{
char peekChar=(char)0;
PeekCh(ref peekChar);
if ('\'' != peekChar) break;
ReadCh();
}
word.Append((char)this.character);
if (!ReadCh()) break;
}
ReadCh();
Emit(ScanSymbols.literal1,word.ToString());
}
public void ScanUnknown()
{
ReadCh();
Emit(ScanSymbols.unknown1);
}
public static String SymbolToLiteralString(Scanner.ScanSymbols code)
{
switch(code)
{
case Scanner.ScanSymbols.directive_clear_modified1 :
return "directive_clear_modified1";
case Scanner.ScanSymbols.declare1 :
return "declare";
case Scanner.ScanSymbols.unknown1 :
return "unknown symbol";
case Scanner.ScanSymbols.assign1 :
return "assignment";
case Scanner.ScanSymbols.if1 :
return "if";
case Scanner.ScanSymbols.while1 :
return "while";
case Scanner.ScanSymbols.for1 :
return "for";
case Scanner.ScanSymbols.then1 :
return "then";
case Scanner.ScanSymbols.else1 :
return "else";
case Scanner.ScanSymbols.goto1 :
return "goto";
case Scanner.ScanSymbols.equal1 :
return "=";
case Scanner.ScanSymbols.equalequal1 :
return "==";
case Scanner.ScanSymbols.less1 :
return "<";
case Scanner.ScanSymbols.lessequal1 :
return "<=";
case Scanner.ScanSymbols.greater1 :
return ">";
case Scanner.ScanSymbols.greaterequal1 :
return ">=";
case Scanner.ScanSymbols.notequal1 :
return "<>";
case Scanner.ScanSymbols.variable1 :
return "variable";
case Scanner.ScanSymbols.asterisk1 :
return "*";
case Scanner.ScanSymbols.apostrophe1 :
return "'";
case Scanner.ScanSymbols.comma1 :
return ",";
case Scanner.ScanSymbols.label1 :
return "label";
case Scanner.ScanSymbols.literal1 :
return "'";
case Scanner.ScanSymbols.leftcurly1 :
return "{";
case Scanner.ScanSymbols.rightcurly1 :
return "}";
case Scanner.ScanSymbols.leftbracket1 :
return "[";
case Scanner.ScanSymbols.rightbracket1 :
return "]";
case Scanner.ScanSymbols.numeral1 :
return "numeral";
case Scanner.ScanSymbols.char1 :
return "character";
case Scanner.ScanSymbols.divide1 :
return "/";
case Scanner.ScanSymbols.plus1 :
return "+";
case Scanner.ScanSymbols.minus1 :
return "-";
case Scanner.ScanSymbols.leftparen1 :
return "(";
case Scanner.ScanSymbols.rightparen1 :
return ")";
case Scanner.ScanSymbols.newline1 :
return "newline";
case Scanner.ScanSymbols.semicolon1 :
return ";";
case Scanner.ScanSymbols.endtext1 :
return ";";
case Scanner.ScanSymbols.end1 :
return "end";
case Scanner.ScanSymbols.andand1 :
return "&&";
case Scanner.ScanSymbols.oror1 :
return "||";
case Scanner.ScanSymbols.abs1 :
return "abs";
case Scanner.ScanSymbols.pow1 :
return "pow";
case Scanner.ScanSymbols.sqrt1 :
return "sqrt";
case Scanner.ScanSymbols.not1 :
return "!";
case Scanner.ScanSymbols.convert1 :
return "convert";
case Scanner.ScanSymbols.in1 :
return "in";
case Scanner.ScanSymbols.like1 :
return "like";
case Scanner.ScanSymbols.trim1 :
return "trim";
case Scanner.ScanSymbols.upper1 :
return "upper";
case Scanner.ScanSymbols.lower1 :
return "lower";
case Scanner.ScanSymbols.substring1 :
return "substring";
case Scanner.ScanSymbols.getprice1 :
return "getprice";
case Scanner.ScanSymbols.null1 :
return "null";
case Scanner.ScanSymbols.isnull1 :
return "isnull";
default :
return "";
}
}
public static String SymbolToString(Scanner.ScanSymbols code)
{
switch(code)
{
case Scanner.ScanSymbols.directive_clear_modified1 :
return "directive_clear_modified1";
case Scanner.ScanSymbols.declare1 :
return "declare1";
case Scanner.ScanSymbols.unknown1 :
return "unknown1";
case Scanner.ScanSymbols.assign1 :
return "assign1";
case Scanner.ScanSymbols.if1 :
return "if1";
case Scanner.ScanSymbols.while1 :
return "while1";
case Scanner.ScanSymbols.for1 :
return "for1";
case Scanner.ScanSymbols.then1 :
return "then1";
case Scanner.ScanSymbols.else1 :
return "else1";
case Scanner.ScanSymbols.goto1 :
return "goto1";
case Scanner.ScanSymbols.equal1 :
return "equal1";
case Scanner.ScanSymbols.equalequal1 :
return "equalequal1";
case Scanner.ScanSymbols.less1 :
return "less1";
case Scanner.ScanSymbols.lessequal1 :
return "lessequal1";
case Scanner.ScanSymbols.greater1 :
return "greater1";
case Scanner.ScanSymbols.greaterequal1 :
return "greaterequal1";
case Scanner.ScanSymbols.notequal1 :
return "notequal1";
case Scanner.ScanSymbols.variable1 :
return "variable1";
case Scanner.ScanSymbols.asterisk1 :
return "asterisk1";
case Scanner.ScanSymbols.apostrophe1 :
return "apostrophe1";
case Scanner.ScanSymbols.comma1 :
return "comma1";
case Scanner.ScanSymbols.label1 :
return "label1";
case Scanner.ScanSymbols.literal1 :
return "literal1";
case Scanner.ScanSymbols.leftcurly1 :
return "leftcurly1";
case Scanner.ScanSymbols.rightcurly1 :
return "rightcurly1";
case Scanner.ScanSymbols.leftbracket1 :
return "leftbracket1";
case Scanner.ScanSymbols.rightbracket1 :
return "rightbracket1";
case Scanner.ScanSymbols.numeral1 :
return "numeral1";
case Scanner.ScanSymbols.char1 :
return "char1";
case Scanner.ScanSymbols.divide1 :
return "divide1";
case Scanner.ScanSymbols.plus1 :
return "plus1";
case Scanner.ScanSymbols.minus1 :
return "minus1";
case Scanner.ScanSymbols.leftparen1 :
return "leftparen1";
case Scanner.ScanSymbols.rightparen1 :
return "rightparen1";
case Scanner.ScanSymbols.newline1 :
return "newline1";
case Scanner.ScanSymbols.semicolon1 :
return "semicolon1";
case Scanner.ScanSymbols.endtext1 :
return "endtext1";
case Scanner.ScanSymbols.end1 :
return "end1";
case Scanner.ScanSymbols.andand1 :
return "andand1";
case Scanner.ScanSymbols.oror1 :
return "oror1";
case Scanner.ScanSymbols.abs1 :
return "abs1";
case Scanner.ScanSymbols.pow1 :
return "pow1";
case Scanner.ScanSymbols.sqrt1 :
return "sqrt1";
case Scanner.ScanSymbols.not1 :
return "not1";
case Scanner.ScanSymbols.convert1 :
return "convert1";
case Scanner.ScanSymbols.in1 :
return "in1";
case Scanner.ScanSymbols.like1 :
return "like1";
case Scanner.ScanSymbols.trim1 :
return "trim1";
case Scanner.ScanSymbols.upper1 :
return "upper1";
case Scanner.ScanSymbols.lower1 :
return "lower1";
case Scanner.ScanSymbols.substring1 :
return "substring1";
case Scanner.ScanSymbols.getprice1 :
return "getprice1";
case Scanner.ScanSymbols.null1 :
return "null1";
case Scanner.ScanSymbols.isnull1 :
return "isnull1";
default :
return "";
}
}
}
}