public ScriptdotnetGrammar(bool expressionGrammar) { #region 1. Terminals NumberLiteral n = TerminalFactory.CreateCSharpNumber("number"); IdentifierTerminal v = CreateScriptNetIdentifier("Identifier"); Terminal s = CreateScriptNetString("string"); Terminal @is = Symbol("is"); Terminal dot = Symbol(".", "dot"); Terminal less = Symbol("<"); Terminal greater = Symbol(">"); Terminal arrow = Symbol("->"); Terminal LSb = Symbol("["); Terminal RSb = Symbol("]"); Terminal LCb = Symbol("("); Terminal RCb = Symbol(")"); Terminal RFb = Symbol("}"); Terminal LFb = Symbol("{"); Terminal LMb = Symbol("<!"); Terminal RMb = Symbol("!>"); Terminal LGb = Symbol("<|"); Terminal RGb = Symbol("|>"); Terminal comma = Symbol(","); Terminal semicolon = Symbol(";"); Terminal colon = Symbol(":"); #endregion #region 2. Non-terminals #region 2.1 Expressions NonTerminal Expr = new NonTerminal("Expr", typeof(ScriptExpr)); NonTerminal ConstExpr = new NonTerminal("ConstExpr", typeof(ScriptConstExpr)); NonTerminal BinExpr = new NonTerminal("BinExpr", typeof(ScriptBinExpr)); NonTerminal UnaryExpr = new NonTerminal("UnaryExpr", typeof(ScriptUnaryExpr)); NonTerminal AssignExpr = new NonTerminal("AssignExpr", typeof(ScriptAssignExpr)); NonTerminal TypeConvertExpr = new NonTerminal("TypeConvertExpr", typeof(ScriptTypeConvertExpr)); NonTerminal IsExpr = new NonTerminal("IsExpr", typeof(ScriptIsExpr)); NonTerminal MetaExpr = new NonTerminal("MetaExpr", typeof(ScriptMetaExpr)); NonTerminal FuncDefExpr = new NonTerminal("FuncDefExpr", typeof(ScriptFunctionDefinition)); //typeof(ScriptFunctionDefExpression)); NonTerminal TypeExpr = new NonTerminal("TypeExpr", typeof(ScriptTypeExpr)); NonTerminal TypeConstructor = new NonTerminal("TypeConstructor", typeof(ScriptTypeConstructor)); NonTerminal FunctionCall = new NonTerminal("FunctionCall", typeof(ScriptFunctionCall)); NonTerminal ArrayResolution = new NonTerminal("ArrayResolution", typeof(ScriptArrayResolution)); NonTerminal BinOp = new NonTerminal("BinOp"); NonTerminal LUnOp = new NonTerminal("LUnOp"); NonTerminal RUnOp = new NonTerminal("RUnOp"); NonTerminal ArrayConstructor = new NonTerminal("ArrayConstructor", typeof(ScriptArrayConstructor)); NonTerminal MObjectConstructor = new NonTerminal("MObjectConstructor", typeof(ScriptMObject)); NonTerminal MObjectPart = new NonTerminal("MObjectPart", typeof(ScriptMObjectPart)); NonTerminal MObjectParts = new NonTerminal("MObjectPart", typeof(ScriptAst)); NonTerminal TypeList = new NonTerminal("TypeList", typeof(ScriptTypeExprList)); #endregion #region 2.2 QualifiedName //Expression List: expr1, expr2, expr3, .. NonTerminal ExprList = new NonTerminal("ExprList", typeof(ScriptExprList)); //A name in form: a.b.c().d[1,2].e .... NonTerminal NewStmt = new NonTerminal("NewStmt", typeof(ScriptNewStmt)); NonTerminal NewArrStmt = new NonTerminal("NewArrStmt", typeof(ScriptNewArrStmt)); NonTerminal QualifiedName = new NonTerminal("QualifiedName", typeof(ScriptQualifiedName)); NonTerminal GenericsPostfix = new NonTerminal("GenericsPostfix", typeof(ScriptGenericsPostfix)); NonTerminal GlobalList = new NonTerminal("GlobalList", typeof(ScriptGlobalList)); #endregion #region 2.3 Statement NonTerminal Condition = new NonTerminal("Condition", typeof(ScriptCondition)); NonTerminal Statement = new NonTerminal("Statement", typeof(ScriptStatement)); NonTerminal IfStatement = new NonTerminal("IfStatement", typeof(ScriptIfStatement)); NonTerminal WhileStatement = new NonTerminal("WhileStatement", typeof(ScriptWhileStatement)); NonTerminal ForStatement = new NonTerminal("ForStatement", typeof(ScriptForStatement)); NonTerminal ForEachStatement = new NonTerminal("ForEachStatement", typeof(ScriptForEachStatement)); NonTerminal OptionalExpression = new NonTerminal("OptionalExpression", typeof(ScriptExpr)); NonTerminal SwitchStatement = new NonTerminal("SwitchStatement", typeof(ScriptStatement)); NonTerminal SwitchStatements = new NonTerminal("SwitchStatements", typeof(ScriptSwitchStatement)); NonTerminal SwitchCaseStatement = new NonTerminal("SwitchCaseStatement", typeof(ScriptSwitchCaseStatement)); NonTerminal SwitchDefaultStatement = new NonTerminal("SwitchDefaultStatement", typeof(ScriptSwitchDefaultStatement)); NonTerminal UsingStatement = new NonTerminal("UsingStatement", typeof(ScriptUsingStatement)); NonTerminal TryCatchFinallyStatement = new NonTerminal("TryCatchFinallyStatement", typeof(ScriptTryCatchFinallyStatement)); NonTerminal FlowControlStatement = new NonTerminal("FlowControl", typeof(ScriptFlowControlStatement)); NonTerminal ExprStatement = new NonTerminal("ExprStatement", typeof(ScriptStatement)); //Block NonTerminal BlockStatement = new NonTerminal("BlockStatement", typeof(ScriptStatement)); NonTerminal Statements = new NonTerminal("Statements(Compound)", typeof(ScriptCompoundStatement)); #endregion #region 2.4 Program and Functions NonTerminal Prog = new NonTerminal("Prog", typeof(ScriptProg)); NonTerminal Element = new NonTerminal("Element", typeof(ScriptAst)); NonTerminal Elements = new NonTerminal("Elements", typeof(ScriptElements)); NonTerminal FuncDef = new NonTerminal("FuncDef", typeof(ScriptFunctionDefinition)); NonTerminal FuncContract = new NonTerminal("FuncContract", typeof(ScriptFuncContract)); NonTerminal ParameterList = new NonTerminal("ParamaterList", typeof(ScriptFuncParameters)); NonTerminal FuncContractPre = new NonTerminal("Pre Conditions", typeof(ScriptFuncContractPre)); NonTerminal FuncContractPost = new NonTerminal("Post Conditions", typeof(ScriptFuncContractPost)); NonTerminal FuncContractInv = new NonTerminal("Invariant Conditions", typeof(ScriptFuncContractInv)); #endregion #endregion #region 3. BNF rules #region 3.1 Expressions ConstExpr.Rule = Symbol("true") | "false" | "null" | s | n; BinExpr.Rule = Expr + BinOp + Expr | IsExpr; UnaryExpr.Rule = LUnOp + Expr; IsExpr.Rule = Expr + @is + TypeExpr; TypeConvertExpr.Rule = LCb + Expr + RCb + Expr.Q(); AssignExpr.Rule = QualifiedName + "=" + Expr | QualifiedName + "++" | QualifiedName + "--" | QualifiedName + ":=" + Expr | QualifiedName + "+=" + Expr | QualifiedName + "-=" + Expr; //TODO: MetaFeatures; // <[ ] + > because of conflict a[1]>2 MetaExpr.Rule = LMb + Elements + RMb; GlobalList.Rule = "global" + LCb + ParameterList + RCb; FuncDefExpr.Rule = "function" + LCb + ParameterList + RCb + GlobalList.Q() + FuncContract.Q() + BlockStatement; Expr.Rule = ConstExpr | BinExpr | UnaryExpr | QualifiedName | AssignExpr | NewStmt | FuncDefExpr | NewArrStmt | ArrayConstructor | MObjectConstructor | TypeConvertExpr | MetaExpr ; NewStmt.Rule = "new" + TypeConstructor; NewArrStmt.Rule = "new" + TypeExpr + ArrayResolution; BinOp.Rule = Symbol("+") | "-" | "*" | "/" | "%" | "^" | "&" | "|" | "&&" | "||" | "==" | "!=" | greater | less | ">=" | "<="; LUnOp.Rule = Symbol("~") | "-" | "!" | "$"; ArrayConstructor.Rule = LSb + ExprList + RSb; MObjectPart.Rule = v + arrow + Expr; MObjectParts.Rule = MakePlusRule(MObjectParts, comma, MObjectPart); MObjectConstructor.Rule = LSb + MObjectParts + RSb; OptionalExpression.Rule = Expr.Q(); #endregion #region 3.2 QualifiedName TypeExpr.Rule = //MakePlusRule(TypeExpr, dot, v); v + GenericsPostfix.Q() | TypeExpr + dot + (v + GenericsPostfix.Q()); GenericsPostfix.Rule = LGb + TypeList + RGb; FunctionCall.Rule = LCb + ExprList.Q() + RCb; ArrayResolution.Rule = LSb + ExprList + RSb; QualifiedName.Rule = v + (GenericsPostfix | ArrayResolution | FunctionCall).Star() | QualifiedName + dot + v + (GenericsPostfix | ArrayResolution | FunctionCall).Star(); ExprList.Rule = MakePlusRule(ExprList, comma, Expr); TypeList.Rule = MakePlusRule(TypeList, comma, TypeExpr); TypeConstructor.Rule = TypeExpr + FunctionCall; #endregion #region 3.3 Statement Condition.Rule = LCb + Expr + RCb; IfStatement.Rule = "if" + Condition + Statement + ("else" + Statement).Q(); WhileStatement.Rule = "while" + Condition + Statement; ForStatement.Rule = "for" + LCb + OptionalExpression + semicolon + OptionalExpression + semicolon + OptionalExpression + RCb + Statement; ForEachStatement.Rule = "foreach" + LCb + v + "in" + Expr + RCb + Statement; UsingStatement.Rule = "using" + LCb + Expr + RCb + BlockStatement; TryCatchFinallyStatement.Rule = "try" + BlockStatement + "catch" + LCb + v + RCb + BlockStatement + "finally" + BlockStatement; SwitchStatement.Rule = "switch" + LCb + Expr + RCb + LFb + SwitchStatements + RFb; ExprStatement.Rule = Expr + semicolon; FlowControlStatement.Rule = "break" + semicolon | "continue" + semicolon | "return" + Expr + semicolon | "throw" + Expr + semicolon; Statement.Rule = semicolon | IfStatement //1. If | WhileStatement //2. While | ForStatement //3. For | ForEachStatement //4. ForEach | UsingStatement //5. Using | SwitchStatement //6. Switch | BlockStatement //7. Block | TryCatchFinallyStatement //8. TryCatch | ExprStatement //9. Expr | FlowControlStatement; //10. FlowControl Statements.SetOption(TermOptions.IsList); Statements.Rule = Statements + Statement | Empty; BlockStatement.Rule = LFb + Statements + RFb; SwitchStatements.Rule = SwitchCaseStatement.Star() + SwitchDefaultStatement.Q(); SwitchCaseStatement.Rule = Symbol("case") + Expr + colon + Statements; SwitchDefaultStatement.Rule = "default" + colon + Statements; #endregion #region 3.4 Prog FuncContract.Rule = LSb + FuncContractPre + semicolon + FuncContractPost + semicolon + FuncContractInv + semicolon + RSb; FuncContractPre.Rule = "pre" + LCb + ExprList.Q() + RCb; FuncContractPost.Rule = "post" + LCb + ExprList.Q() + RCb; FuncContractInv.Rule = "invariant" + LCb + ExprList.Q() + RCb; ParameterList.Rule = MakeStarRule(ParameterList, comma, v); FuncDef.Rule = "function" + v + LCb + ParameterList + RCb + GlobalList.Q() + FuncContract.Q() + BlockStatement; Element.Rule = Statement | FuncDef; Elements.SetOption(TermOptions.IsList); Elements.Rule = Elements + Element | Empty; Prog.Rule = Elements + Eof; Terminal Comment = new CommentTerminal("Comment", "/*", "*/"); NonGrammarTerminals.Add(Comment); Terminal LineComment = new CommentTerminal("LineComment", "//", "\n"); NonGrammarTerminals.Add(LineComment); #endregion #endregion #region 4. Set starting symbol if (!expressionGrammar) Root = Prog; // Set grammar root else Root = Expr; #endregion #region 5. Operators precedence RegisterOperators(1, "=", "+=", "-=", ":="); RegisterOperators(2, "|", "||"); RegisterOperators(3, "&", "&&"); RegisterOperators(4, "==", "!=", ">", "<", ">=", "<="); RegisterOperators(5, "is"); RegisterOperators(6, "+", "-"); RegisterOperators(7, "*", "/", "%"); RegisterOperators(8, Associativity.Right, "^"); RegisterOperators(9, "~", "!", "$", "++", "--"); RegisterOperators(10, "."); //RegisterOperators(10, Associativity.Right, ".",",", ")", "(", "]", "[", "{", "}"); //RegisterOperators(11, Associativity.Right, "else"); #endregion #region 6. Punctuation symbols RegisterPunctuation( "(", ")", "[", "]", "{", "}", ",", ";" ); #endregion }
public BasicGrammar() { #region Initialisation // BASIC is not case sensitive... this.CaseSensitive = false; // By default, new-line characters are ignored. Because BASIC uses // line breaks to delimit lines, we need to know where the line breaks // are. The following line is required for this. this.TokenFilters.Add(new CodeOutlineFilter(false)); // Define the Terminals Terminal number = new NumberLiteral("NUMBER"); VariableIdentifierTerminal variable = new VariableIdentifierTerminal(); Terminal stringLiteral = new StringLiteral("STRING", "\"", ScanFlags.None); //Important: do not add comment term to base.NonGrammarTerminals list - we do use this terminal in grammar rules Terminal comment = new CommentTerminal("Comment", "REM", "\n"); Terminal comma = Symbol(",", "comma"); // Make sure reserved keywords of the BASIC language aren't mistaken // for variables. Only the keywords ending with '$' could be mistaken // for variables. variable.AddKeywords( "inkey$", "left$", "right$", "mid$", "chr$", "space$", "str$", "string$" ); // Define the non-terminals NonTerminal PROGRAM = new NonTerminal("PROGRAM", typeof(ProgramNode)); NonTerminal LINE = new NonTerminal("LINE", typeof(LineNode)); NonTerminal STATEMENT_LIST = new NonTerminal("STATEMENT_LIST", typeof(StatementListNode)); NonTerminal STATEMENT = new NonTerminal("STATEMENT", typeof(StatementNode)); NonTerminal COMMAND = new NonTerminal("COMMAND", typeof(StatementNode)); //TODO: create command node NonTerminal PRINT_STMT = new NonTerminal("PRINT_STMT", typeof(PrintStmtNode)); NonTerminal INPUT_STMT = new NonTerminal("INPUT_STMT", typeof(InputStmtNode)); NonTerminal IF_STMT = new NonTerminal("IF_STMT", typeof(IfElseStmtNode)); //TODO: join IfStmtNode and IfElseStmtNode in one NonTerminal ELSE_CLAUSE_OPT = new NonTerminal("ELSE_CLAUSE_OPT", typeof(GenericJsBasicNode)); NonTerminal EXPR = new NonTerminal("EXPRESSION", typeof(ExpressionNode)); NonTerminal EXPR_LIST = new NonTerminal("EXPRESSION_LIST", typeof(ExprListNode)); NonTerminal BINARY_OP = new NonTerminal("BINARY_OP", typeof(BinaryOpNode)); NonTerminal BINARY_EXPR = new NonTerminal("BINARY_EXPR", typeof(GenericJsBasicNode)); //TODO: create Binary_expr node NonTerminal BRANCH_STMT = new NonTerminal("BRANCH_STMT", typeof(BranchStmtNode)); NonTerminal ASSIGN_STMT = new NonTerminal("ASSIGN_STMT", typeof(AssignStmtNode)); NonTerminal FOR_STMT = new NonTerminal("FOR_STMT", typeof(ForStmtNode)); NonTerminal STEP_OPT = new NonTerminal("STEP_OPT", typeof(GenericJsBasicNode)); //TODO: create step specifier node NonTerminal NEXT_STMT = new NonTerminal("NEXT_STMT", typeof(NextStmtNode)); NonTerminal LOCATE_STMT = new NonTerminal("LOCATE_STMT", typeof(LocateStmtNode)); NonTerminal WHILE_STMT = new NonTerminal("WHILE_STMT", typeof(WhileStmtNode)); NonTerminal WEND_STMT = new NonTerminal("WEND_STMT", typeof(WendStmtNode)); NonTerminal SWAP_STMT = new NonTerminal("SWAP_STMT", typeof(SwapStmtNode)); NonTerminal GLOBAL_FUNCTION_EXPR = new NonTerminal("GLOBAL_FUNCTION_EXPR", typeof(GlobalFunctionExpr)); NonTerminal ARG_LIST = new NonTerminal("ARG_LIST", typeof(GenericJsBasicNode)); NonTerminal FUNC_NAME = new NonTerminal("FUNC_NAME", typeof(GenericJsBasicNode)); NonTerminal COMMENT_STMT = new NonTerminal("COMMENT_STMT", typeof(RemStmtNode)); NonTerminal GLOBAL_VAR_EXPR = new NonTerminal("GLOBAL_VAR_EXPR", typeof(GenericJsBasicNode)); // Set the PROGRAM to be the root node of BASIC programs. // A program is a bunch of lines this.Root = PROGRAM; #endregion #region Grammar declaration // A program is a collection of lines PROGRAM.Rule = MakePlusRule(PROGRAM, null, LINE); // A line can be an empty line, or it's a number followed by a statement list ended by a new-line. LINE.Rule = NewLine | number + NewLine | number + STATEMENT_LIST + NewLine; // A statement list is 1 or more statements separated by the ':' character STATEMENT_LIST.Rule = MakePlusRule(STATEMENT_LIST, Symbol(":"), STATEMENT); // A statement can be one of a number of types STATEMENT.Rule = EXPR | ASSIGN_STMT | PRINT_STMT | INPUT_STMT | IF_STMT | COMMENT_STMT | BRANCH_STMT | COMMAND | FOR_STMT | NEXT_STMT | LOCATE_STMT | SWAP_STMT | WHILE_STMT | WEND_STMT; // The different statements are defined here PRINT_STMT.Rule = "print" + EXPR_LIST; INPUT_STMT.Rule = "input" + EXPR_LIST + variable; IF_STMT.Rule = "if" + EXPR + "then" + STATEMENT_LIST + ELSE_CLAUSE_OPT; ELSE_CLAUSE_OPT.Rule = Empty | "else" + STATEMENT_LIST; BRANCH_STMT.Rule = "goto" + number | "gosub" + number | "return"; ASSIGN_STMT.Rule = variable + "=" + EXPR; LOCATE_STMT.Rule = "locate" + EXPR + comma + EXPR; SWAP_STMT.Rule = "swap" + EXPR + comma + EXPR; COMMAND.Rule = Symbol("end") | "cls"; COMMENT_STMT.Rule = comment; // An expression is a number, or a variable, a string, or the result of a binary comparison. EXPR.Rule = number | variable | stringLiteral | BINARY_EXPR | GLOBAL_VAR_EXPR | GLOBAL_FUNCTION_EXPR | "(" + EXPR + ")"; BINARY_EXPR.Rule = EXPR + BINARY_OP + EXPR; BINARY_OP.Rule = Symbol("+") | "-" | "*" | "/" | "=" | "<=" | ">=" | "<" | ">" | "<>" | "and" | "or"; //let's do operator precedence right here RegisterOperators(50, "*", "/"); RegisterOperators(40, "+", "-"); RegisterOperators(30, "=", "<=", ">=", "<", ">", "<>"); RegisterOperators(20, "and", "or"); // Used by print and input to allow a bunch of expressions separated by whitespace, // or be empty, for example: // print // print "Hi" // print "Hi " a$ // All of these match "print" EXPR_LIST EXPR_LIST.Rule = MakeStarRule(EXPR_LIST, null, EXPR); FOR_STMT.Rule = "for" + ASSIGN_STMT + "to" + EXPR + STEP_OPT; STEP_OPT.Rule = Empty | "step" + number; NEXT_STMT.Rule = "next" + variable; WHILE_STMT.Rule = "while" + EXPR; WEND_STMT.Rule = "wend"; //TODO: check number of arguments for particular function in node constructor GLOBAL_FUNCTION_EXPR.Rule = FUNC_NAME + "(" + ARG_LIST + ")"; FUNC_NAME.Rule = Symbol("len") | "left$" | "mid$" | "right$" | "abs" | "asc" | "chr$" | "csrlin$" | "cvi" | "cvs" | "cvd" | "exp" | "fix" | "log" | "pos" | "sgn" | "sin" | "cos" | "tan" | "instr" | "space$" | "spc" | "sqr" | "str$" | "string$" | "val" | "cint"; ARG_LIST.Rule = MakePlusRule(ARG_LIST, comma, EXPR); GLOBAL_VAR_EXPR.Rule = Symbol("rnd") | "timer" | "inkey$" | "csrlin"; // By registering these strings as "punctuation", we exclude them from // appearing in as nodes in the compiled node tree. RegisterPunctuation("(", ")", ","); #endregion }