using System; using System.Text; using System.Collections.Generic; using csmic; COMPILER INTERPRETER /* * Class structures and helpers */ private FunctionValue functionValue = new FunctionValue(); public FunctionValue Result { get { return this.functionValue; } set { this.functionValue = value; } } private InputInterpreter interpreter = null; public InputInterpreter Interpreter { get { return this.interpreter; } set { this.interpreter = value; } } bool IsFunctionCall() { scanner.ResetPeek(); Token next = scanner.Peek(); if (next.kind == _LPAREN && la.kind == _identifier) return true; return false; } bool IsCompare() { scanner.ResetPeek(); Token next = scanner.Peek(); if (next.kind == _COMPARER) return true; return false; } bool IsAssignment() { scanner.ResetPeek(); Token next = scanner.Peek(); if (next.val == "::" || next.val == ":=" || next.val == "->") return true; return false; } bool IsArrayCall() { scanner.ResetPeek(); Token next = scanner.Peek(); if (next.val == "[") return true; return false; } /* * Character sets and tokens */ CHARACTERS UpperLetter = 'A'..'Z'. LowerLetter = 'a'..'z'. letter = UpperLetter + LowerLetter. digit = "0123456789" . cr = '\r' . lf = '\n' . tab = '\t' . PM = "+-" . NoQuote = ANY - '\"' . TOKENS identifier = letter { letter | digit}. sign = PM . binary = ( '0' | '1' ) { '0' | '1' } ('B' | 'b') . hex = "0x" ( digit | ('A' | 'B' | 'C' | 'D' | 'E' |'F') | ('a' | 'b' | 'c' | 'd' | 'e' |'f') ) { digit | ('A' | 'B' | 'C' | 'D' | 'E' |'F') | ('a' | 'b' | 'c' | 'd' | 'e' |'f') } . number = digit { digit }['.' {digit}] [('E'|'e')['+'|'-'] digit {digit}] . string = "\"" { NoQuote } "\"" . LPAREN = '(' . RPAREN = ')' . COMPARER = "==" | "<" | ">" | "<=" | ">=" . IGNORE cr + tab /* * Grammar */ PRODUCTIONS INTERPRETER (. FunctionValue fv = new FunctionValue(); bool success = true; if (this.interpreter == null) { return; } .) = IF(IsCompare()) Comparison (. this.functionValue = (success == true) ? FunctionValue.TRUE : FunctionValue.FALSE; this.interpreter.ProduceOutput(this.functionValue); .) | IF(IsAssignment()) Assignment (. this.functionValue = new FunctionValue(ValueType.Numeric, r); this.interpreter.ProduceOutput(this.functionValue); .) | Expression (. this.functionValue = new FunctionValue(ValueType.Numeric, r); this.interpreter.ProduceOutput(this.functionValue); .) . Expression = (. decimal r1 = 0; r = 0; .) Term { '+' Term (. r += r1; .) | '-' Term (. r -= r1; .) } . Term = (. decimal r1 = 0; r = 0; .) Factor { '*' Factor (. r *= r1; .) | '/' Factor (. r /= r1; .) | '%' Term (. r %= r1; .) } . Factor = (. decimal r1 = 0; .) Value { '^' Expression (. r = Convert.ToDecimal(Math.Pow(Convert.ToDouble(r), Convert.ToDouble(r1))); .) } . Value (. r = 0; decimal r1 = 0; int signum = 1; FunctionValue fvr = new FunctionValue(); string ident = string.Empty; .) = [ '+' | '-' (. signum = -1; .) ] ( IF(IsFunctionCall()) Function (. if (fvr.Type == ValueType.Numeric && fvr.Value != null) { try { r = signum * Convert.ToDecimal(fvr.Value); } catch { SemErr("function returned non-numeric"); r = 0; } } else { SemErr("function returned a string; number required"); r = 0; } .) | IF(IsArrayCall()) ArrayCall (. r = signum * r; .) | identifier (. ident = t.val; decimal temp = 0; string expr = string.Empty; bool ok = false; // Prefer numeric binding try { // runtime method expected ok = this.interpreter.TryGetNumeric(ident, out temp); } catch { ok = false; } if (ok) { r = signum * temp; } else { // Check expression binding try { if (this.interpreter.TryGetExpression(ident, out expr)) { FunctionValue eval = this.interpreter.EvaluateExpression(expr); if (eval.Type == ValueType.Numeric && eval.Value != null) { r = signum * Convert.ToDecimal(eval.Value); } else { SemErr("expression variable did not evaluate to a number"); r = 0; } } else { SemErr("variable '" + ident + "' is not numeric"); r = 0; } } catch { SemErr("error evaluating expression variable"); r = 0; } } .) | number (. r = signum * Convert.ToDecimal(t.val); .) | hex (. string hx = t.val.Remove(0,2); try { r = signum * Convert.ToDecimal(Convert.ToInt64(hx, 16)); } catch { r = 0; } .) | binary (. string bx = t.val.Remove(t.val.Length - 1); try { r = signum * Convert.ToDecimal(Convert.ToInt64(bx, 2)); } catch { r = 0; } .) | '(' Expression ')' (. r = signum * r; .) ) . ArrayL = (. List list = new List(); decimal r = 0; d = new decimal[0]; .) '[' Expression (. list.Add(r); d = list.ToArray(); .) { ',' Expression (. list.Add(r); d = list.ToArray(); .) } ']' . ArrayCall (. string ident = string.Empty; r = 0; decimal pos = 0; .) = identifier (. ident = t.val; .) '[' Expression (. try { int i = Convert.ToInt32(pos); decimal[] values; if (this.interpreter.TryGetNumericArray(ident, out values)) { if (i >= 0 && i < values.Length) { r = values[i]; } else { SemErr("array index out of range"); r = 0; } } else { SemErr("variable '" + ident + "' is not a numeric array"); r = 0; } } catch { SemErr("invalid array index"); r = 0; } .) ']' . Assignment (. string identifier = string.Empty; string expression = string.Empty; decimal[] d = new decimal[0]; r = 0; .) = identifier (. identifier = t.val; .) ( ( "::" Expression (. this.interpreter.AssignNumeric(identifier, r); .) ) | ( ":=" AnyExpression (. this.interpreter.AssignExpression(identifier, expression); r = 0; .) ) | ( "->" ArrayL (. this.interpreter.AssignNumericArray(identifier, d); r = 0; .) ) ) . // Function call with mixed arguments (numeric expressions and strings) Function (. string functionName = string.Empty; FunctionArgument[] args = new FunctionArgument[0]; r = new FunctionValue(); .) = identifier (. functionName = t.val; .) '(' ArgList ')' (. r = this.interpreter.ExecuteFunction(functionName, args); .) . ArgList (. List list = new List(); FunctionArgument a = new FunctionArgument { Name = string.Empty, Value = new FunctionValue() }; args = new FunctionArgument[0]; .) = [ Arg (. list.Add(a); args = list.ToArray(); .) { ',' Arg (. list.Add(a); args = list.ToArray(); .) } ] . Arg (. arg = new FunctionArgument { Name = string.Empty, Value = new FunctionValue() }; decimal r = 0; string s = string.Empty; .) = ( string (. s = t.val.Substring(1, t.val.Length - 2); arg = new FunctionArgument { Name = string.Empty, Value = new FunctionValue(ValueType.String, s) }; .) | Expression (. arg = new FunctionArgument { Name = string.Empty, Value = new FunctionValue(ValueType.Numeric, r) }; .) ) . Comparison (. decimal firstValue = 0; decimal secondValue = 0; string compareType = string.Empty; result = false; .) = Expression COMPARER (. compareType = t.val; .) Expression (. switch(compareType) { case "==": result = (firstValue == secondValue); break; case ">": result = (firstValue > secondValue); break; case "<": result = (firstValue < secondValue); break; case ">=": result = (firstValue >= secondValue); break; case "<=": result = (firstValue <= secondValue); break; default: result = false; break; } .) . AnyExpression (. value = string.Empty; StringBuilder builder = new StringBuilder(); .) = ANY (. builder.Append(t.val); .) { ANY (. builder.Append(t.val); .) } (. value = builder.ToString(); .) . END INTERPRETER.