/// <summary> /// Create a binary expression /// </summary> public SyntaxExpr(Token function, SyntaxExpr param1, SyntaxExpr param2) { mParameters = new List <SyntaxExpr>(); mFunction = function; mParameters.Add(param1); mParameters.Add(param2); }
/// <summary> /// Make a bit declaration. First parameter is declaration (with optional /// array parameter). Second parameter is optional assignment. /// </summary> public SyntaxExpr ParseBitStatement(string[] rejects) { // Create "bit" statement SyntaxExpr expr = new SyntaxExpr(Accept("bit")); if (mToken.Type != eTokenType.Identifier) { Reject("Expecting a variable name", rejects); return(expr); } // Create declaration (array size is optional parameter) Token variableName = Accept(); SyntaxExpr declaration = new SyntaxExpr(variableName); if (mTokenName == "[") { declaration.AddParam(ParseParen()); } // First parameter is declaration expr.AddParam(declaration); // Second parameter (optional) is assignment statement if (mTokenName == "=") { expr.AddParam(new SyntaxExpr(Accept(), new SyntaxExpr(variableName), ParseExpr())); } return(expr); }
/// <summary> /// Parse multiple statements until 'box', 'end', 'else', or 'elif' /// is found. Returns the statements that are parsed. /// Adds declarations to the box locals. Never returns NULL. /// </summary> public SyntaxExpr ParseStatements(SyntaxBox box, bool topLevel) { // Create an "{" expression, which (for now means "statements") SyntaxExpr statements = new SyntaxExpr(mInternalTokenStatement); // While not end of file and not end of box and not new box while (mTokenName != "" && mTokenName != "box" && mTokenName != "end" && mTokenName != "else" && mTokenName != "elif") { // Skip blank statements while (mTokenName == ";") { Accept(); } // Parse the statement SyntaxExpr statement = ParseStatement(box, topLevel); if (statement != null) { statements.AddParam(statement); } while (mTokenName == ";") { Accept(); } } return(statements); }
/// <summary> /// Parse a constant declaration (only "int" type is supported) /// </summary> SyntaxExpr ParseConstStatement() { // Create "const" statement SyntaxExpr expr = new SyntaxExpr(Accept("const")); if (mTokenName != "int") { Reject("Expecting keyword 'int'", REJECT_LINE); return(expr); } // First parameter is the type, "int" expr.AddParam(new SyntaxExpr(Accept())); // Variable name must be identifier if (mToken.Type != eTokenType.Identifier) { Reject("Expecting a variable name", REJECT_LINE); return(expr); } Token variableName = Accept(); // Const statement requires an assignment if (mTokenName != "=") { Reject("Expecting '=' - Assignment is required"); return(expr); } // Second parameter is the assignment expression expr.AddParam(new SyntaxExpr(Accept(), new SyntaxExpr(variableName), ParseExpr())); return(expr); }
/// <summary> /// Append a parameter to the parameters list. /// </summary> public void AddParam(SyntaxExpr e) { if (mParameters == null) { mParameters = new List <SyntaxExpr>(); } mParameters.Add(e); }
/// <summary> /// Parse an array or function call /// </summary> SyntaxExpr ParseExprArrayOrFunction() { SyntaxExpr result = ParseExprAtom(); if (mTokenName == "(" || mTokenName == "[") { result = ParseParameters(result); } return(result); }
/// <summary> /// Parse an expression /// </summary> public SyntaxExpr ParseExpr() { SyntaxExpr result = ParseExprTernary(); // Optionally build a range function if (mTokenName == ":" || mTokenName == "..") { return(new SyntaxExpr(Accept(), result, ParseExprTernary())); } return(result); }
/// <summary> /// Parse equality /// </summary> SyntaxExpr ParseExprCompare() { SyntaxExpr result = ParseExprPlus(); // Optionally build equality function if (mTokenName == "==" || mTokenName == "!=") { return(new SyntaxExpr(Accept(), result, ParseExprPlus())); } return(result); }
/// <summary> /// Parse (*, /, %) /// </summary> SyntaxExpr ParseExprMult() { SyntaxExpr result = ParseUnary(); // Build multiplication function while (mTokenName == "*" || mTokenName == "/" || mTokenName == "%") { result = new SyntaxExpr(Accept(), result, ParseUnary()); } return(result); }
/// <summary> /// Parse (+, -) /// </summary> SyntaxExpr ParseExprPlus() { SyntaxExpr result = ParseExprXor(); // Build addition function while (mTokenName == "+" || mTokenName == "-") { result = new SyntaxExpr(Accept(), result, ParseExprXor()); } return(result); }
/// <summary> /// Parse an if statement (expects 'if' at the input) /// </summary> SyntaxExpr ParseIfStatement(SyntaxBox box) { // Parse "if" token, condition, and statements Token ifToken = mToken; Accept("if"); SyntaxExpr ifExpr = new SyntaxExpr(ifToken); ifExpr.AddParam(ParseIfCond()); ifExpr.AddParam(ParseStatements(box, false)); // Parse "elif" statements SyntaxExpr elseExpr = ifExpr; while (mTokenName == "elif") { // Parse "elif" token, condition, and statements // NOTE: "elif" token is converted to "if" Connect(ifToken, mToken); Accept("elif"); SyntaxExpr newIf = new SyntaxExpr(ifToken); newIf.AddParam(ParseIfCond()); newIf.AddParam(ParseStatements(box, false)); // Convert the new "elif" to "else if" elseExpr.AddParam(newIf); elseExpr = newIf; } // Parse the "else" clause (if it exists) if (mTokenName == "else") { Connect(ifToken, mToken); Accept("else"); elseExpr.AddParam(ParseStatements(box, false)); } // Parse end of box statement if (mTokenName == "end") { mToken.InfoString = "end if"; Connect(ifToken, mToken); Accept(); } else { Reject("Expecting 'end' - end of if statement body", REJECT_BOX); } // Parse "else" part return(ifExpr); }
/// <summary> /// Parse parameters '(' param1 ',' param2 ... ')' /// NOTE: firstParam is the function name, and will be the first /// parameter of the result. The open and close '()' or '[]' will /// be connected. /// </summary> SyntaxExpr ParseParameters(SyntaxExpr firstParam) { // Read open '(' or '[' Token openToken = mToken; if (openToken != "(" && openToken != "[") { throw new Exception("Compiler error: Expecting '(' or '[' while parsing parameters"); } // Create an expression with '(' or '[' SyntaxExpr result = new SyntaxExpr(Accept(), firstParam); string tokenExpected = openToken == "(" ? ")" : "]"; string [] rejectTokens = openToken == "(" ? REJECT_PAREN : REJECT_BRACKET; // Empty () function call? if (mTokenName == tokenExpected) { // Return an empty () or [] Connect(openToken, mToken); Accept(); return(result); } // Parse all parameters result.AddParam(ParseExpr()); while (mTokenName == ",") { Accept(); result.AddParam(ParseExpr()); } // If not ended properly, reject this expression if (mTokenName != tokenExpected) { // The rest of the line is rejected Reject("Expecting '" + tokenExpected + "' or ','", rejectTokens); } if (mTokenName == tokenExpected) { Connect(openToken, mToken); Accept(); } return(result); }
/// <summary> /// Parse ternary expression (a ? (b : c)) /// </summary> SyntaxExpr ParseExprTernary() { SyntaxExpr result = ParseExprCompare(); // Or a ternary operator if (mTokenName == "?") { Token q = Accept(); SyntaxExpr t1 = ParseExprTernary(); if (mTokenName != ":") { q.Reject("Matching ':' was not found"); return(Reject("Expecting a ':' to separate expression for the ternary '?' operator", REJECT_LINE)); } result = new SyntaxExpr(q, result, new SyntaxExpr(Accept(), t1, ParseExprTernary())); } return(result); }
/// <summary> /// Parse an 'if' or 'elif' condition /// </summary> SyntaxExpr ParseIfCond() { // Parse condition if (mTokenName != "(") { return(Reject("Expecting '('", REJECT_LINE)); } Token open = Accept(); SyntaxExpr result = ParseExpr(); if (mTokenName != ")") { return(Reject("Expecting ')' - end of of expression", REJECT_LINE)); } Connect(open, mToken); Accept(")"); return(result); }
/// <summary> /// Read the open '(' or '[' parse the expression and connect /// the ']' or ')'. Returns the expression that was parsed. /// </summary> SyntaxExpr ParseParen() { // Shouldn't ever happen if (mTokenName != "(" && mTokenName != "[") { throw new Exception("Compiler error: Expecting '[' or '(' while parsing paren"); } // Read open '(' or '[' and create an Expr Token openToken = mToken; string tokenExpected = openToken == "(" ? ")" : "]"; string [] rejectTokens = openToken == "(" ? REJECT_PAREN : REJECT_BRACKET; Accept(); // Empty () or []? if (mTokenName == tokenExpected) { // Return an empty () or [] Connect(openToken, mToken); Reject("Expecting a parameter"); SyntaxExpr emptyExpr = new SyntaxExpr(Accept()); // Error, use ')' or ']' return(emptyExpr); } // Parse all parameters (then add separator) SyntaxExpr result = ParseExpr(); // If not ended properly, append a reject line if (mTokenName != tokenExpected) { // The rest of the line is rejected Reject("Expecting '" + tokenExpected + "'", rejectTokens); } if (mTokenName == tokenExpected) { Connect(openToken, mToken); Accept(); } return(result); }
/// <summary> /// Generate an expression list (as if this were lisp) /// </summary> void ToString(SyntaxExpr expr, StringBuilder sb, int level) { if (level >= 7) { sb.Append("*OVF*"); return; } if (Count == 0) { sb.Append(expr.mFunction); return; } if (level != 0) { sb.Append("("); } if (expr.mFunction == "(") { sb.Append("'"); } sb.Append(expr.mFunction); if (expr.mFunction == "(") { sb.Append("'"); } foreach (SyntaxExpr param in expr.mParameters) { sb.Append(", "); ToString(param, sb, level + 1); } if (level != 0) { sb.Append(")"); } }
/// <summary> /// Rejects tokens until one of the stopTokens is found. /// Marks at least one token with the error message. /// </summary> SyntaxExpr Reject(string errorMessage, string [] stopTokens) { // Mark all tokens to end of line with an error Reject(errorMessage); SyntaxExpr result = new SyntaxExpr(mToken); // Skip the rest of this statement while (true) { if (mTokenName == "") { return(result); } foreach (string token in stopTokens) { if (mTokenName == token) { return(result); } } Accept(); } }
/// <summary> /// Evaluate a constant. If there is an error, the symbol /// that caused it is rejected and the error bit is set. /// </summary> public static EvaluateConst Eval(SymbolTable symbols, SyntaxExpr expr) { if (expr == null) { return(new EvaluateConst()); } if (expr.Count != 0) { expr.Function.Reject("Not yet supported"); return(new EvaluateConst()); } if (expr.Function.Name.Length == 0) { return(new EvaluateConst()); } // Parse number if (char.IsDigit(expr.Function.Name[0])) { EvaluateConst result = new EvaluateConst(); result.Resolved = true; // Attempt to scan hexadecimal value if (expr.Function.Name.Length >= 3 && char.ToUpper(expr.Function.Name[1]) == 'X' && long.TryParse(expr.Function.Name.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture, out result.ValueInt)) { result.WasHex = true; return(result); } // Attempt to scan decimal value if (long.TryParse(expr.Function.Name, out result.ValueInt)) { return(result); } expr.Function.Reject("Error reading value"); return(new EvaluateConst()); } // Parse identifier if (expr.Function.Type == eTokenType.Identifier) { Symbol symbol = symbols.FindSymbol(expr.Function); if (symbol == null) { expr.Function.Reject("Undefined symbol"); return(new EvaluateConst()); } if (symbol.Decl.TypeName.Name != "int") { expr.Function.Reject("Constant value must be of type 'int'"); return(new EvaluateConst()); } if (symbol.ResolvedName == "") { expr.Function.Reject("Unresolved symbol"); return(new EvaluateConst()); } // We got the type, mark the symbol expr.Function.AppendMessage(symbol.ResolvedName); return(new EvaluateConst(symbol.ConstValue)); } expr.Function.Reject("Unrecognized symbol in constant expression"); return(new EvaluateConst()); }
/// <summary> /// Parse a single statement, which could be an expression. /// Adds declaratins to the box locals. /// NOTE: This can return NULL if there are no statements. /// </summary> public SyntaxExpr ParseStatement(SyntaxBox box, bool topLevel) { while (mTokenName == "else" || mTokenName == "elif") { Reject("This '" + mTokenName + "' is not inside an 'if' statement"); Accept(); } // Check statement keywords first bool needsSemicolon = true; SyntaxExpr result = null; if (mTokenName == "bit") { // Parse bit statement (optionally followed by assignment) if (!topLevel) { Reject("'bit' declarations are only allowed at the top level"); } result = ParseBitStatement(REJECT_LINE); } else if (mTokenName == "const") { // Parse const declaration if (!topLevel) { Reject("'const' declarations are only allowed at the top level"); } result = ParseConstStatement(); } else if (mTokenName == "if") { // Parse if statement needsSemicolon = false; result = ParseIfStatement(box); } else { // Parse an expression result = ParseExpr(); // Assignment statement? if (mTokenName == "=") { // Generate an assignment statement result = new SyntaxExpr(Accept(), result, ParseExpr()); } } // Ensure we have a valid statement if (needsSemicolon && mTokenName != ";") { Reject("Expecting end of statement separator ';'", REJECT_LINE); } if (mTokenName == ";") { Accept(); } return(result); }