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 ""; } } } }