public ExpressionEvaluatorGrammar() { // 1. Terminals var number = new NumberLiteral("number"); var identifier = new IdentifierTerminal("identifier"); var comment = new CommentTerminal("comment", "#", "\n", "\r"); base.NonGrammarTerminals.Add(comment); // 2. Non-terminals var Variable = new NonTerminal("Variable", typeof(VarRefNode)); var Expr = new NonTerminal("Expr"); var Term = new NonTerminal("Term"); var BinExpr = new NonTerminal("BinExpr", typeof(BinExprNode)); var ParExpr = new NonTerminal("ParExpr"); var UnExpr = new NonTerminal("UnExpr", typeof(UnExprNode)); var UnOp = new NonTerminal("UnOp"); var BinOp = new NonTerminal("BinOp"); var AssignmentStmt = new NonTerminal("AssignmentStmt", typeof(AssigmentNode)); var Statement = new NonTerminal("Statement"); var ProgramLine = new NonTerminal("ProgramLine"); var Program = new NonTerminal("Program", typeof(StatementListNode)); // 3. BNF rules Variable.Rule = identifier; Expr.Rule = Term | UnExpr | BinExpr; Term.Rule = number | ParExpr | Variable; ParExpr.Rule = "(" + Expr + ")"; UnExpr.Rule = UnOp + Term; UnOp.Rule = Symbol("+") | "-"; BinExpr.Rule = Expr + BinOp + Expr; BinOp.Rule = Symbol("+") | "-" | "*" | "/" | "**"; AssignmentStmt.Rule = Variable + "=" + Expr; Statement.Rule = AssignmentStmt | Expr | Empty; ProgramLine.Rule = Statement + NewLine; Program.Rule = MakeStarRule(Program, ProgramLine); this.Root = Program; // Set grammar root // 4. Operators precedence RegisterOperators(1, "+", "-"); RegisterOperators(2, "*", "/"); RegisterOperators(3, Associativity.Right, "**"); RegisterPunctuation( "(", ")"); MarkTransient(Term, Expr, Statement); //automatically add NewLine before EOF so that our BNF rules work correctly when there's no final line break in source this.LanguageFlags |= LanguageFlags.NewLineBeforeEOF | LanguageFlags.SupportsInterpreter; }
public GWBasicGrammar() { #region Initialisation // BASIC is not case sensitive... this.CaseSensitive = false; // Define the Terminals var lineNumber = new NumberLiteral("NUMBER", NumberFlags.IntOnly); var fileNumber = new NumberLiteral("NUMBER", NumberFlags.IntOnly); var number = new NumberLiteral("NUMBER", NumberFlags.AllowStartEndDot); var variable = new IdentifierTerminal("Identifier", "$%!", string.Empty); var stringLiteral = new StringLiteral("STRING", "\"", StringFlags.None); //Important: do not add comment term to base.NonGrammarTerminals list - we do use this terminal in grammar rules var userFunctionName = variable; var comment = new CommentTerminal("Comment", "REM", "\n"); var short_comment = new CommentTerminal("ShortComment", "'", "\n"); var comma = Symbol(",", "comma"); var colon = Symbol(":", "colon"); var comma_opt = new NonTerminal("comma_opt"); comma_opt.Rule = Empty | ","; var semi_opt = new NonTerminal("semi_opt"); semi_opt.Rule = Empty | ";"; var pound_opt = new NonTerminal("pound_opt"); pound_opt.Rule = Empty | "#"; // Define the non-terminals var PROGRAM = new NonTerminal("PROGRAM"); var LINE = new NonTerminal("LINE"); var LINE_CONTENT = new NonTerminal("LINE_CONTENT"); var SHORT_COMMENT_OPT = new NonTerminal("SHORT_COMMENT_OPT"); var STATEMENT_LIST = new NonTerminal("STATEMENT_LIST"); var STATEMENT = new NonTerminal("STATEMENT"); var PRINT_STMT = new NonTerminal("PRINT_STMT"); var PRINT_LIST = new NonTerminal("PRINT_LIST"); var PRINT_ARG = new NonTerminal("PRINT_ARG"); var OPEN_STMT = new NonTerminal("OPEN_STMT"); var OPEN_STMT_MODE = new NonTerminal("OPEN_STMT_MODE"); var OPEN_STMT_ACCESS = new NonTerminal("OPEN_STMT_ACCESS"); var CLOSE_STMT = new NonTerminal("CLOSE_STMT"); var INPUT_STMT = new NonTerminal("INPUT_STMT"); var VARIABLES = new NonTerminal("VARIABLES"); var IF_STMT = new NonTerminal("IF_STMT"); var THEN_CLAUSE = new NonTerminal("THEN_CLAUSE"); var ELSE_CLAUSE_OPT = new NonTerminal("ELSE_CLAUSE_OPT"); //, typeof(AstNode)); var EXPR = new NonTerminal("EXPRESSION"); var EXPR_LIST = new NonTerminal("EXPRESSION_LIST"); var BINARY_OP = new NonTerminal("BINARY_OP"); var BINARY_EXPR = new NonTerminal("BINARY_EXPR"); var UNARY_EXPR = new NonTerminal("UNARY_EXPR"); var SIGN = new NonTerminal("SIGN"); var ASSIGN_STMT = new NonTerminal("ASSIGN_STMT"); var FOR_STMT = new NonTerminal("FOR_STMT"); var STEP_OPT = new NonTerminal("STEP_OPT"); var NEXT_STMT = new NonTerminal("NEXT_STMT"); var LOCATE_STMT = new NonTerminal("LOCATE_STMT"); var WHILE_STMT = new NonTerminal("WHILE_STMT"); var WEND_STMT = new NonTerminal("WEND_STMT"); var SWAP_STMT = new NonTerminal("SWAP_STMT"); var FUN_CALL = new NonTerminal("FUN_CALL"); var VARIABLE_OR_FUNCTION_EXPR = new NonTerminal("VARIABLE_OR_FUNCTION_EXPR"); var ARG_LIST = new NonTerminal("ARG_LIST"); var COMMENT_STMT = new NonTerminal("COMMENT_STMT"); var LINE_INPUT_STMT = new NonTerminal("LINE_INPUT_STMT"); var LINE_INPUT_POUND_STMT = new NonTerminal("LINE_INPUT_POUND_STMT"); var END_STMT = new NonTerminal("END_STMT"); var CLS_STMT = new NonTerminal("CLS_STMT", typeof(AstNode)); var CLEAR_STMT = new NonTerminal("CLEAR_STMT"); var DIM_STMT = new NonTerminal("DIM_STMT"); var DEF_FN_STMT = new NonTerminal("DEF_FN_STMT"); var GOTO_STMT = new NonTerminal("GOTO_STMT"); var GOSUB_STMT = new NonTerminal("GOSUB_STMT"); var RETURN_STMT = new NonTerminal("RETURN_STMT"); var ON_STMT = new NonTerminal("ON_STMT"); var LINE_NUMBERS = new NonTerminal("LINE_NUMBERS"); var RANDOMIZE_STMT = new NonTerminal("RANDOMIZE_STMT"); // set the PROGRAM to be the root node of BASIC programs. this.Root = PROGRAM; #endregion #region Grammar declaration // A program is a bunch of lines PROGRAM.Rule = MakePlusRule(PROGRAM, 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 | lineNumber + LINE_CONTENT + SHORT_COMMENT_OPT + NewLine; // A statement list is 1 or more statements separated by the ':' character LINE_CONTENT.Rule = IF_STMT | COMMENT_STMT | STATEMENT_LIST; STATEMENT_LIST.Rule = MakePlusRule(STATEMENT_LIST, colon, STATEMENT); SHORT_COMMENT_OPT.Rule = short_comment | Empty; // A statement can be one of a number of types STATEMENT.Rule = ASSIGN_STMT | PRINT_STMT | INPUT_STMT | OPEN_STMT | CLOSE_STMT | LINE_INPUT_POUND_STMT | LINE_INPUT_STMT | LOCATE_STMT | CLS_STMT | END_STMT | CLEAR_STMT | DIM_STMT | DEF_FN_STMT | SWAP_STMT | RANDOMIZE_STMT | GOSUB_STMT | RETURN_STMT | GOTO_STMT | ON_STMT | FOR_STMT | NEXT_STMT | WHILE_STMT | WEND_STMT; // The different statements are defined here PRINT_STMT.Rule = "print" + PRINT_LIST; PRINT_LIST.Rule = MakeStarRule(PRINT_LIST, null, PRINT_ARG); PRINT_ARG.Rule = EXPR + semi_opt; INPUT_STMT.Rule = "input" + semi_opt + stringLiteral + ";" + VARIABLES; OPEN_STMT.Rule = "open" + EXPR + (Empty | "for" + OPEN_STMT_MODE) + (Empty | "access" + OPEN_STMT_ACCESS) + "as" + pound_opt + fileNumber; OPEN_STMT_ACCESS.Rule = "read" + (Empty | "write") | "write"; OPEN_STMT_MODE.Rule = Symbol("o") | "i" | "a" | "output" | "input" | "append"; CLOSE_STMT.Rule = "close" + pound_opt + number; LINE_INPUT_STMT.Rule = Symbol("line") + "input" + semi_opt + stringLiteral + ";" + VARIABLE_OR_FUNCTION_EXPR; LINE_INPUT_POUND_STMT.Rule = Symbol("line") + "input" + Symbol("#") + fileNumber + comma + VARIABLE_OR_FUNCTION_EXPR; DIM_STMT.Rule = "dim" + VARIABLES; DEF_FN_STMT.Rule = "def" + userFunctionName + (Empty | "(" + ARG_LIST + ")") + "=" + EXPR; VARIABLES.Rule = VARIABLE_OR_FUNCTION_EXPR | VARIABLE_OR_FUNCTION_EXPR + "," + VARIABLES; IF_STMT.Rule = "if" + EXPR + THEN_CLAUSE + ELSE_CLAUSE_OPT; THEN_CLAUSE.Rule = "then" + STATEMENT_LIST | "goto" + lineNumber; //Inject PreferShift hint here to explicitly set shift as preferred action. Suppresses warning message about conflict. ELSE_CLAUSE_OPT.Rule = Empty | PreferShiftHere() + "else" + STATEMENT_LIST; GOTO_STMT.Rule = "goto" + lineNumber; GOSUB_STMT.Rule = "gosub" + lineNumber; RETURN_STMT.Rule = "return"; ON_STMT.Rule = "on" + EXPR + (Symbol("goto") | "gosub") + LINE_NUMBERS; LINE_NUMBERS.Rule = lineNumber + (Empty | "," + LINE_NUMBERS); ASSIGN_STMT.Rule = VARIABLE_OR_FUNCTION_EXPR + "=" + EXPR; LOCATE_STMT.Rule = "locate" + EXPR + comma + EXPR; SWAP_STMT.Rule = "swap" + EXPR + comma + EXPR; END_STMT.Rule = "end"; CLS_STMT.Rule = "cls"; CLEAR_STMT.Rule = Symbol("clear") + comma + (Empty | number) + (Empty | comma + number) | "clear" + number | "clear"; COMMENT_STMT.Rule = comment | short_comment; RANDOMIZE_STMT.Rule = "randomize" + EXPR; // An expression is a number, or a variable, a string, or the result of a binary comparison. EXPR.Rule = number | variable | FUN_CALL | stringLiteral | BINARY_EXPR | "(" + EXPR + ")" | UNARY_EXPR; BINARY_EXPR.Rule = EXPR + BINARY_OP + EXPR; UNARY_EXPR.Rule = SIGN + EXPR; SIGN.Rule = Symbol("-") | "+"; //Inject PreferShift hint here to explicitly set shift as preferred action. Suppresses warning message about conflict. FUN_CALL.Rule = variable + PreferShiftHere() + "(" + ARG_LIST + ")"; VARIABLE_OR_FUNCTION_EXPR.Rule = variable | FUN_CALL; BINARY_OP.Rule = Symbol("+") | "^" | "-" | "*" | "/" | "=" | "<=" | ">=" | "<" | ">" | "<>" | "and" | "or"; //let's do operator precedence right here RegisterOperators(60, "^"); RegisterOperators(50, "*", "/"); RegisterOperators(40, "+", "-"); RegisterOperators(30, "=", "<=", ">=", "<", ">", "<>"); RegisterOperators(20, "and", "or"); EXPR_LIST.Rule = MakeStarRule(EXPR_LIST, null, EXPR); FOR_STMT.Rule = "for" + ASSIGN_STMT + "to" + EXPR + STEP_OPT; STEP_OPT.Rule = Empty | "step" + EXPR; NEXT_STMT.Rule = "next" + VARIABLES | "next"; WHILE_STMT.Rule = "while" + EXPR; WEND_STMT.Rule = "wend"; //TODO: check number of arguments for particular function in node constructor ARG_LIST.Rule = MakePlusRule(ARG_LIST, comma, EXPR); #endregion #region Punctuation RegisterPunctuation("(", ")", ",", ";"); #endregion }
public ScriptdotnetGrammar() { #region 1. Terminals NumberLiteral n = TerminalFactory.CreateCSharpNumber("number"); IdentifierTerminal v = new IdentifierTerminal("Identifier"); /* v.AddReservedWords("true", "false", "null", "if", "else", "while", "for", "foreach", "in", "switch", "case", "default", "break", "continue", "return", "function", "is", "pre", "post", "invariant", "new"); */ StringLiteral s = new StringLiteral("String", "'", StringFlags.AllowsDoubledQuote); 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 comma = Symbol(","); Terminal semicolon = Symbol(";"); Terminal colon = Symbol(":"); #endregion #region 2. Non-terminals #region 2.1 Expressions NonTerminal Expr = new NonTerminal("Expr"); NonTerminal BinOp = new NonTerminal("BinOp"); NonTerminal LUnOp = new NonTerminal("LUnOp"); NonTerminal RUnOp = new NonTerminal("RUnOp"); NonTerminal ArrayConstructor = new NonTerminal("ArrayConstructor"); NonTerminal MObjectConstructor = new NonTerminal("MObjectConstructor"); NonTerminal MObjectList = new NonTerminal("MObjectList"); #endregion #region 2.2 QualifiedName //Expression List: expr1, expr2, expr3, .. NonTerminal ExprList = new NonTerminal("ExprList"); //A name in form: a.b.c().d[1,2].e .... NonTerminal NewStmt = new NonTerminal("NewStmt"); NonTerminal NewArrStmt = new NonTerminal("NewArrStmt"); NonTerminal QualifiedName = new NonTerminal("QualifiedName"); NonTerminal GenericsPostfix = new NonTerminal("GenericsPostfix"); NonTerminal ArrayExpression = new NonTerminal("ArrayExpression"); NonTerminal FunctionExpression = new NonTerminal("FunctionExpression"); #endregion #region 2.3 Statement NonTerminal Condition = new NonTerminal("Condition"); NonTerminal Statement = new NonTerminal("Statement"); NonTerminal Statements = new NonTerminal("Statements"); //Block NonTerminal CompoundStatement = new NonTerminal("CompoundStatement"); #endregion #region 2.4 Program and Functions NonTerminal Prog = new NonTerminal("Prog"); NonTerminal Element = new NonTerminal("Element"); NonTerminal FuncDef = new NonTerminal("FuncDef"); NonTerminal FuncContract = new NonTerminal("FuncContract"); NonTerminal ParameterListOpt = new NonTerminal("ParamaterListOpt"); NonTerminal SwitchStatements = new NonTerminal("SwitchStatements"); #endregion #endregion #region 3. BNF rules #region 3.1 Expressions Expr.Rule = Symbol("true") | "false" | "null" | s | n | QualifiedName // The following is needed: to parse "A<B ..." either as comparison or as beginning of GenericsPostfix | QualifiedName + less + Expr | QualifiedName + less + QualifiedName + greater | NewStmt | NewArrStmt | QualifiedName + ":=" + Expr | ArrayExpression | FunctionExpression | ArrayConstructor | MObjectConstructor | Expr + BinOp + Expr | LUnOp + Expr | Expr + RUnOp | LMb + Element.Star() + RMb | LCb + Expr + RCb ; ExprList.Rule = MakePlusRule(ExprList, comma, Expr); NewStmt.Rule = "new" + QualifiedName + GenericsPostfix.Q() + LCb + ExprList.Q() + RCb; NewArrStmt.Rule = "new" + QualifiedName + GenericsPostfix.Q() + LSb + ExprList.Q() + RSb; BinOp.Rule = Symbol("+") | "-" | "*" | "/" | "%" | "^" | "&" | "|" | "&&" | "||" | "==" | "!=" | greater | less | ">=" | "<=" | "is" | "=" | "+=" | "-=" | "."; LUnOp.Rule = Symbol("-") | "~" | "!"; RUnOp.Rule = Symbol("++") | "--"; ArrayConstructor.Rule = LSb + ExprList + RSb; MObjectConstructor.Rule = LSb + v + arrow + Expr + MObjectList.Star() + RSb; MObjectList.Rule = comma + v + arrow + Expr; #endregion #region 3.2 QualifiedName ArrayExpression.Rule = QualifiedName + LSb + ExprList + RSb; FunctionExpression.Rule = QualifiedName + LCb + ExprList.Q() + RCb; QualifiedName.Rule = v | QualifiedName + dot + v; GenericsPostfix.Rule = less + QualifiedName + greater; //ExprList.Rule = Expr.Plus(comma); #endregion #region 3.3 Statement Condition.Rule = LCb + Expr + RCb; Statement.Rule = semicolon | "if" + Condition + Statement | "if" + Condition + Statement + "else" + Statement | "while" + Condition + Statement | "for" + LCb + Expr.Q() + semicolon + Expr.Q() + semicolon + Expr.Q() + RCb + Statement | "foreach" + LCb + v + "in" + Expr + RCb + Statement | "switch" + LCb + Expr + RCb + LFb + SwitchStatements + RFb | CompoundStatement | Expr + semicolon | "break" + semicolon | "continue" + semicolon | "return" + Expr + semicolon; Statements.Rule = MakeStarRule(Statements, null, Statement); CompoundStatement.Rule = LFb + Statements + RFb; SwitchStatements.Rule = Symbol("case") + Expr + colon + Statements + SwitchStatements | "default" + colon + Statements; #endregion #region 3.4 Prog Prog.Rule = Element.Star() + Eof; FuncContract.Rule = LSb + "pre" + LCb + ExprList.Q() + RCb + semicolon + "post" + LCb + ExprList.Q() + RCb + semicolon + "invariant" + LCb + ExprList.Q() + RCb + semicolon + RSb; ParameterListOpt.Rule = MakeStarRule(ParameterListOpt, comma, v); FuncDef.Rule = "function" + v + LCb + ParameterListOpt.Q() + RCb + FuncContract.Q() + CompoundStatement; Element.Rule = Statement | FuncDef; Terminal Comment = new CommentTerminal("Comment", "/*", "*/"); NonGrammarTerminals.Add(Comment); Terminal LineComment = new CommentTerminal("LineComment", "//", "\n"); NonGrammarTerminals.Add(LineComment); #endregion #endregion #region 4. Set starting symbol this.Root = Prog; // Set grammar root #endregion #region 5. Operators precedence RegisterOperators(1, "=", "+=", "-="); RegisterOperators(2, "+", "-"); RegisterOperators(3, "*", "/", "%"); RegisterOperators(4, Associativity.Right, "^"); RegisterOperators(5, "|", "||"); RegisterOperators(6, "&", "&&"); RegisterOperators(7, "==", "!=", ">", "<" , ">=", "<="); RegisterOperators(8, "is"); RegisterOperators(9, "~", "!", "++", "--"); RegisterOperators(10, "."); //RegisterOperators(10, Associativity.Right, ".",",", ")", "(", "]", "[", "{", "}"); //RegisterOperators(11, Associativity.Right, "else"); #endregion #region 6. Punctuation symbols RegisterPunctuation( "(", ")", "[", "]", "{", "}", ",", ";" ); #endregion }
public CSharpGrammar() { #region Lexical structure StringLiteral StringLiteral = TerminalFactory.CreateCSharpString("StringLiteral"); StringLiteral CharLiteral = TerminalFactory.CreateCSharpChar("CharLiteral"); NumberLiteral Number = TerminalFactory.CreateCSharpNumber("Number"); IdentifierTerminal identifier = TerminalFactory.CreateCSharpIdentifier("Identifier"); CommentTerminal SingleLineComment = new CommentTerminal("SingleLineComment", "//", "\r", "\n", "\u2085", "\u2028", "\u2029"); CommentTerminal DelimitedComment = new CommentTerminal("DelimitedComment", "/*", "*/"); NonGrammarTerminals.Add(SingleLineComment); NonGrammarTerminals.Add(DelimitedComment); //Temporarily, treat preprocessor instructions like comments CommentTerminal ppInstruction = new CommentTerminal("ppInstruction", "#", "\n"); NonGrammarTerminals.Add(ppInstruction); //Symbols SymbolTerminal colon = Symbol(":", "colon"); SymbolTerminal semi = Symbol(";", "semi"); NonTerminal semi_opt = new NonTerminal("semi?"); semi_opt.Rule = Empty | semi; SymbolTerminal dot = Symbol(".", "dot"); SymbolTerminal comma = Symbol(",", "comma"); NonTerminal comma_opt = new NonTerminal("comma_opt", Empty | comma); NonTerminal commas_opt = new NonTerminal("commas_opt"); commas_opt.Rule = MakeStarRule(commas_opt, null, comma); SymbolTerminal qmark = Symbol("?", "qmark"); NonTerminal qmark_opt = new NonTerminal("qmark_opt", Empty | qmark); SymbolTerminal Lbr = Symbol("{"); SymbolTerminal Rbr = Symbol("}"); SymbolTerminal Lpar = Symbol("("); SymbolTerminal Rpar = Symbol(")"); SymbolTerminal tgoto = Symbol("goto"); SymbolTerminal yld = Symbol("yield"); SymbolTerminal Lparx = Symbol("(*"); #region operators, punctuation and delimiters RegisterOperators(1, "||"); RegisterOperators(2, "&&"); RegisterOperators(3, "|"); RegisterOperators(4, "^"); RegisterOperators(5, "&"); RegisterOperators(6, "==", "!="); RegisterOperators(7, "<", ">", "<=", ">=", "is", "as"); RegisterOperators(8, "<<", ">>"); RegisterOperators(9, "+", "-"); RegisterOperators(10, "*", "/", "%"); RegisterOperators(11, "."); // RegisterOperators(12, "++", "--"); #region comments //The following makes sense, if you think about "?" in context of operator precedence. // What we say here is that "?" has the lowest priority among arithm operators. // Therefore, the parser should prefer reduce over shift when input symbol is "?". // For ex., when seeing ? in expression "a + b?...", the parser will perform Reduce: // (a + b)->expr // and not shift the "?" symbol. // Same goes for ?? symbol #endregion RegisterOperators(-3, "=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>="); RegisterOperators(-2, "?"); RegisterOperators(-1, "??"); this.Delimiters = "{}[](),:;+-*/%&|^!~<>="; this.RegisterPunctuation(";", ",", "(", ")", "{", "}", "[", "]", ":"); //Whitespace and NewLine characters //TODO: // 1. In addition to "normal" whitespace chars, the spec mentions "any char of unicode class Z" - // need to create special comment-based terminal that simply eats these category-based whitechars and produces comment token. // 2. Add support for multiple line terminators to LineComment this.LineTerminators = "\r\n\u2085\u2028\u2029"; //CR, linefeed, nextLine, LineSeparator, paragraphSeparator this.WhitespaceChars = " \t\r\n\v\u2085\u2028\u2029"; //add extra line terminators #endregion #endregion #region NonTerminals //B.2.1. Basic concepts NonTerminal qual_name_with_targs = new NonTerminal("qual_name_with_targs"); NonTerminal base_type_list = new NonTerminal("base_type_list"); NonTerminal generic_dimension_specifier = new NonTerminal("generic_dimension_specifier"); NonTerminal qual_name_segment = new NonTerminal("qual_name_segment"); NonTerminal qual_name_segments_opt = new NonTerminal("qual_name_segments_opt"); NonTerminal type_or_void = new NonTerminal("type_or_void"); NonTerminal builtin_type = new NonTerminal("builtin_type"); NonTerminal type_ref_list = new NonTerminal("type_ref_list"); NonTerminal identifier_ext = new NonTerminal("identifier_ext"); NonTerminal identifier_or_builtin = new NonTerminal("identifier_or_builtin"); //B.2.2. Types NonTerminal type_ref = new NonTerminal("type_ref"); NonTerminal new_type_ref = new NonTerminal("new_type_ref"); NonTerminal type_argument_list = new NonTerminal("type_argument_list"); NonTerminal type_argument_list_opt = new NonTerminal("type_argument_list_opt"); NonTerminal integral_type = new NonTerminal("integral_type"); //B.2.4. Expressions NonTerminal argument = new NonTerminal("argument"); NonTerminal argument_list = new NonTerminal("argument_list"); NonTerminal argument_list_opt = new NonTerminal("argument_list_opt"); NonTerminal expression = new NonTerminal("expression"); NonTerminal expression_list = new NonTerminal("expression_list"); NonTerminal expression_opt = new NonTerminal("expression_opt"); NonTerminal conditional_expression = new NonTerminal("conditional_expression"); NonTerminal lambda_expression = new NonTerminal("lambda_expression"); NonTerminal query_expression = new NonTerminal("query_expression"); NonTerminal unary_operator = new NonTerminal("unary_operator"); NonTerminal assignment_operator = new NonTerminal("assignment_operator"); NonTerminal primary_expression = new NonTerminal("primary_expression"); NonTerminal pre_incr_decr_expression = new NonTerminal("pre_incr_decr_expression"); NonTerminal post_incr_decr_expression = new NonTerminal("post_incr_decr_expression"); NonTerminal primary_no_array_creation_expression = new NonTerminal("primary_no_array_creation_expression"); NonTerminal literal = new NonTerminal("literal"); NonTerminal parenthesized_expression = new NonTerminal("parenthesized_expression"); NonTerminal member_access = new NonTerminal("member_access"); NonTerminal member_access_segment = new NonTerminal("member_access_segment"); NonTerminal member_access_segments_opt = new NonTerminal("member_access_segments_opt"); NonTerminal array_indexer = new NonTerminal("array_indexer"); NonTerminal argument_list_par = new NonTerminal("argument_list_par"); NonTerminal argument_list_par_opt = new NonTerminal("argument_list_par_opt"); NonTerminal incr_or_decr = new NonTerminal("incr_or_decr"); NonTerminal incr_or_decr_opt = new NonTerminal("incr_or_decr_opt"); NonTerminal creation_args = new NonTerminal("creation_args"); NonTerminal object_creation_expression = new NonTerminal("object_creation_expression"); // delegate creation is syntactically equiv to object creation //NonTerminal delegate_creation_expression = new NonTerminal("delegate_creation_expression"); NonTerminal anonymous_object_creation_expression = new NonTerminal("anonymous_object_creation_expression"); NonTerminal typeof_expression = new NonTerminal("typeof_expression"); NonTerminal checked_expression = new NonTerminal("checked_expression"); NonTerminal unchecked_expression = new NonTerminal("unchecked_expression"); NonTerminal default_value_expression = new NonTerminal("default_value_expression"); NonTerminal anonymous_method_expression = new NonTerminal("anonymous_method_expression"); NonTerminal elem_initializer = new NonTerminal("elem_initializer"); NonTerminal elem_initializer_list = new NonTerminal("elem_initializer_list"); NonTerminal elem_initializer_list_ext = new NonTerminal("elem_initializer_list_ext"); NonTerminal initializer_value = new NonTerminal("initializer_value"); NonTerminal anonymous_object_initializer = new NonTerminal("anonymous_object_initializer"); NonTerminal member_declarator = new NonTerminal("member_declarator"); NonTerminal member_declarator_list = new NonTerminal("member_declarator_list"); NonTerminal unbound_type_name = new NonTerminal("unbound_type_name"); NonTerminal generic_dimension_specifier_opt = new NonTerminal("generic_dimension_specifier_opt"); NonTerminal anonymous_function_signature = new NonTerminal("anonymous_function_signature"); NonTerminal anonymous_function_signature_opt = new NonTerminal("anonymous_function_signature_opt"); NonTerminal anonymous_function_parameter = new NonTerminal("anonymous_function_parameter"); NonTerminal anonymous_function_parameter_decl = new NonTerminal("anonymous_function_parameter_decl"); NonTerminal anonymous_function_parameter_list_opt = new NonTerminal("anonymous_function_parameter_list_opt"); NonTerminal anonymous_function_parameter_modifier_opt = new NonTerminal("anonymous_function_parameter_modifier_opt"); NonTerminal anonymous_function_body = new NonTerminal("anonymous_function_body"); NonTerminal lambda_function_signature = new NonTerminal("lambda_function_signature"); NonTerminal bin_op_expression = new NonTerminal("bin_op_expression"); NonTerminal typecast_expression = new NonTerminal("typecast_expression"); NonTerminal bin_op = new NonTerminal("bin_op"); //B.2.5. Statements NonTerminal statement = new NonTerminal("statement"); NonTerminal statement_list = new NonTerminal("statement_list"); NonTerminal statement_list_opt = new NonTerminal("statement_list_opt"); NonTerminal labeled_statement = new NonTerminal("labeled_statement"); NonTerminal declaration_statement = new NonTerminal("declaration_statement"); NonTerminal embedded_statement = new NonTerminal("embedded_statement"); NonTerminal selection_statement = new NonTerminal("selection_statement"); NonTerminal iteration_statement = new NonTerminal("iteration_statement"); NonTerminal jump_statement = new NonTerminal("jump_statement"); NonTerminal try_statement = new NonTerminal("try_statement"); NonTerminal checked_statement = new NonTerminal("checked_statement"); NonTerminal unchecked_statement = new NonTerminal("unchecked_statement"); NonTerminal lock_statement = new NonTerminal("lock_statement"); NonTerminal using_statement = new NonTerminal("using_statement"); NonTerminal yield_statement = new NonTerminal("yield_statement"); NonTerminal block = new NonTerminal("block"); NonTerminal statement_expression = new NonTerminal("statement_expression"); NonTerminal statement_expression_list = new NonTerminal("statement_expression_list"); NonTerminal local_variable_declaration = new NonTerminal("local_variable_declaration"); NonTerminal local_constant_declaration = new NonTerminal("local_constant_declaration"); NonTerminal local_variable_type = new NonTerminal("local_variable_type"); NonTerminal local_variable_declarator = new NonTerminal("local_variable_declarator"); NonTerminal local_variable_declarators = new NonTerminal("local_variable_declarators"); NonTerminal local_variable_initializer = new NonTerminal("local_variable_initializer"); NonTerminal if_statement = new NonTerminal("if_statement"); NonTerminal switch_statement = new NonTerminal("switch_statement"); NonTerminal else_clause_opt = new NonTerminal("else_clause_opt"); NonTerminal switch_section = new NonTerminal("switch_section"); NonTerminal switch_sections_opt = new NonTerminal("switch_sections_opt"); NonTerminal switch_label = new NonTerminal("switch_label"); NonTerminal switch_labels = new NonTerminal("switch_labels"); NonTerminal while_statement = new NonTerminal("while_statement"); NonTerminal do_statement = new NonTerminal("do_statement"); NonTerminal for_statement = new NonTerminal("for_statement"); NonTerminal foreach_statement = new NonTerminal("foreach_statement"); NonTerminal for_initializer_opt = new NonTerminal("for_initializer_opt"); NonTerminal for_condition_opt = new NonTerminal("for_condition_opt"); NonTerminal for_iterator_opt = new NonTerminal("for_iterator_opt"); NonTerminal break_statement = new NonTerminal("break_statement"); NonTerminal continue_statement = new NonTerminal("continue_statement"); NonTerminal goto_statement = new NonTerminal("goto_statement"); NonTerminal return_statement = new NonTerminal("return_statement"); NonTerminal throw_statement = new NonTerminal("throw_statement"); NonTerminal try_clause = new NonTerminal("try_clause"); NonTerminal try_clauses = new NonTerminal("try_clauses"); NonTerminal catch_clause = new NonTerminal("catch_clause"); NonTerminal finally_clause = new NonTerminal("finally_clause"); NonTerminal catch_specifier_opt = new NonTerminal("catch_specifier_opt"); NonTerminal identifier_opt = new NonTerminal("identifier_opt"); NonTerminal resource_acquisition = new NonTerminal("resource_acquisition"); //namespaces, compilation units NonTerminal compilation_unit = new NonTerminal("compilation_unit"); NonTerminal extern_alias_directive = new NonTerminal("extern_alias_directive"); NonTerminal extern_alias_directives_opt = new NonTerminal("extern_alias_directives_opt"); NonTerminal using_directive = new NonTerminal("using_directive"); NonTerminal using_directives = new NonTerminal("using_directives"); NonTerminal using_directives_opt = new NonTerminal("using_directives_opt"); NonTerminal namespace_declaration = new NonTerminal("namespace_declaration"); NonTerminal namespace_declarations_opt = new NonTerminal("namespace_declarations_opt"); NonTerminal qualified_identifier = new NonTerminal("qualified_identifier"); NonTerminal namespace_body = new NonTerminal("namespace_body"); NonTerminal namespace_member_declaration = new NonTerminal("namespace_member_declaration"); NonTerminal namespace_member_declarations = new NonTerminal("namespace_member_declarations"); NonTerminal using_alias_directive = new NonTerminal("using_alias_directive"); NonTerminal using_ns_directive = new NonTerminal("using_ns_directive"); NonTerminal type_declaration = new NonTerminal("type_declaration"); NonTerminal class_declaration = new NonTerminal("class_declaration"); NonTerminal delegate_declaration = new NonTerminal("delegate_declaration"); NonTerminal qualified_alias_member = new NonTerminal("qualified_alias_member"); NonTerminal class_body = new NonTerminal("class_body"); //B.2.7 Classes Terminal partial = Symbol("partial"); NonTerminal type_parameter_list_opt = new NonTerminal("type_parameter_list_opt"); NonTerminal type_parameter = new NonTerminal("type_parameter"); NonTerminal type_parameters = new NonTerminal("type_parameters"); NonTerminal bases_opt = new NonTerminal("bases_opt"); NonTerminal type_parameter_constraints_clause = new NonTerminal("type_parameter_constraints_clause"); NonTerminal type_parameter_constraints_clauses_opt = new NonTerminal("type_parameter_constraints_clauses"); NonTerminal type_parameter_constraint = new NonTerminal("type_parameter_constraint"); NonTerminal type_parameter_constraints = new NonTerminal("type_parameter_constraints"); NonTerminal member_declaration = new NonTerminal("member_declaration"); NonTerminal member_declarations_opt = new NonTerminal("member_declarations_opt"); NonTerminal constant_declaration = new NonTerminal("constant_declaration"); NonTerminal field_declaration = new NonTerminal("field_declaration"); NonTerminal method_declaration = new NonTerminal("method_declaration"); NonTerminal property_declaration = new NonTerminal("property_declaration"); NonTerminal event_declaration = new NonTerminal("event_declaration"); NonTerminal indexer_declaration = new NonTerminal("indexer_declaration"); NonTerminal constructor_declaration = new NonTerminal("constructor_declaration"); NonTerminal destructor_declaration = new NonTerminal("destructor_declaration"); NonTerminal constant_declarator = new NonTerminal("constant_declarator"); NonTerminal constant_declarators = new NonTerminal("constant_declarators"); NonTerminal modifier = new NonTerminal("modifier"); NonTerminal modifiers_opt = new NonTerminal("modifiers_opt"); NonTerminal member_header = new NonTerminal("member_header"); NonTerminal accessor_name = new NonTerminal("accessor_name"); NonTerminal accessor_declaration = new NonTerminal("accessor_declaration"); NonTerminal accessor_declarations = new NonTerminal("accessor_declarations"); NonTerminal accessor_modifier_opt = new NonTerminal("accessor_modifier_opt"); NonTerminal event_body = new NonTerminal("event_body"); NonTerminal event_accessor_declarations = new NonTerminal("event_accessor_declarations"); NonTerminal add_accessor_declaration = new NonTerminal("add_accessor_declaration"); NonTerminal remove_accessor_declaration = new NonTerminal("remove_accessor_declaration"); NonTerminal indexer_name = new NonTerminal("indexer_name"); NonTerminal operator_declaration = new NonTerminal("operator_declaration"); NonTerminal conversion_operator_declaration = new NonTerminal("conversion_operator_declaration"); NonTerminal overloadable_operator = new NonTerminal("overloadable_operator"); NonTerminal operator_parameter = new NonTerminal("operator_parameter"); NonTerminal operator_parameters = new NonTerminal("operator_parameters"); NonTerminal conversion_operator_kind = new NonTerminal("conversion_operator_kind"); NonTerminal constructor_initializer_opt = new NonTerminal("constructor_initializer_opt"); NonTerminal constructor_base = new NonTerminal("constructor_base"); NonTerminal variable_declarator = new NonTerminal("variable_declarator"); NonTerminal variable_declarators = new NonTerminal("variable_declarators"); NonTerminal method_body = new NonTerminal("method_body"); NonTerminal formal_parameter_list = new NonTerminal("formal_parameter_list"); NonTerminal formal_parameter_list_par = new NonTerminal("formal_parameter_list_par"); NonTerminal fixed_parameter = new NonTerminal("fixed_parameter"); NonTerminal fixed_parameters = new NonTerminal("fixed_parameters"); NonTerminal parameter_modifier_opt = new NonTerminal("parameter_modifier_opt"); NonTerminal parameter_array = new NonTerminal("parameter_array"); //B.2.8 struct NonTerminal struct_declaration = new NonTerminal("struct_declaration"); NonTerminal struct_body = new NonTerminal("struct_body"); //B.2.9. Arrays NonTerminal rank_specifier = new NonTerminal("rank_specifier"); NonTerminal rank_specifiers = new NonTerminal("rank_specifiers"); NonTerminal rank_specifiers_opt = new NonTerminal("rank_specifiers_opt"); NonTerminal dim_specifier = new NonTerminal("dim_specifier"); NonTerminal dim_specifier_opt = new NonTerminal("dim_specifier_opt"); NonTerminal list_initializer = new NonTerminal("array_initializer"); NonTerminal list_initializer_opt = new NonTerminal("array_initializer_opt"); //B.2.10 Interfaces NonTerminal interface_declaration = new NonTerminal("interface_declaration"); NonTerminal interface_body = new NonTerminal("interface_body"); NonTerminal interface_member_declaration = new NonTerminal("interface_member_declaration"); NonTerminal interface_member_declarations = new NonTerminal("interface_member_declarations"); NonTerminal interface_method_declaration = new NonTerminal("interface_method_declaration"); NonTerminal interface_property_declaration = new NonTerminal("interface_property_declaration"); NonTerminal interface_event_declaration = new NonTerminal("interface_event_declaration"); NonTerminal interface_indexer_declaration = new NonTerminal("interface_indexer_declaration"); NonTerminal new_opt = new NonTerminal("new_opt"); NonTerminal interface_accessor = new NonTerminal("interface_get_accessor"); NonTerminal interface_accessors = new NonTerminal("interface_accessors"); //B.2.11 Enums NonTerminal enum_declaration = new NonTerminal("enum_declaration"); NonTerminal enum_base_opt = new NonTerminal("enum_base_opt"); NonTerminal enum_body = new NonTerminal("enum_body"); NonTerminal enum_member_declaration = new NonTerminal("enum_member_declaration"); NonTerminal enum_member_declarations = new NonTerminal("enum_member_declarations"); //B.2.13 Attributes NonTerminal attribute_section = new NonTerminal("attribute_section"); NonTerminal attributes_opt = new NonTerminal("attributes_opt"); NonTerminal attribute_target_specifier_opt = new NonTerminal("attribute_target_specifier_opt"); NonTerminal attribute_target = new NonTerminal("attribute_target"); NonTerminal attribute = new NonTerminal("attribute"); NonTerminal attribute_list = new NonTerminal("attribute_list"); NonTerminal attribute_arguments_opt = new NonTerminal("attribute_arguments"); NonTerminal named_argument = new NonTerminal("named_argument"); NonTerminal attr_arg = new NonTerminal("attr_arg"); NonTerminal attribute_arguments_par_opt = new NonTerminal("attribute_arguments_par_opt"); #endregion #region Keywords string strKeywords = "abstract as base bool break byte case catch char checked " + "class const continue decimal default delegate do double else enum event explicit extern false finally " + "fixed float for foreach goto if implicit in int interface internal is lock long namespace " + "new null object operator out override params private protected public " + "readonly ref return sbyte sealed short sizeof stackalloc static string " + "struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual void " + "volatile while"; AddKeywordList(strKeywords); #endregion // RULES //B.2.1. Basic concepts //qual_name_with_targs is an alias for namespace-name, namespace-or-type-name, type-name, generic_dimension_specifier.Rule = "<" + commas_opt + ">"; qual_name_segments_opt.Rule = MakeStarRule(qual_name_segments_opt, null, qual_name_segment); identifier_or_builtin.Rule = identifier | builtin_type; identifier_ext.Rule = identifier_or_builtin | "this" | "base"; qual_name_segment.Rule = dot + identifier | "::" + identifier | type_argument_list; generic_dimension_specifier.Rule = "<" + commas_opt + ">"; qual_name_with_targs.Rule = identifier_or_builtin + qual_name_segments_opt; type_argument_list.Rule = "<" + type_ref_list + ">"; type_argument_list_opt.Rule = Empty | type_argument_list; //B.2.2. Types type_or_void.Rule = qual_name_with_targs | "void"; builtin_type.Rule = integral_type | "bool" | "decimal" | "float" | "double" | "string" | "object"; type_ref.Rule = type_or_void + qmark_opt + rank_specifiers_opt + generic_dimension_specifier_opt; type_ref_list.Rule = MakePlusRule(type_ref_list, comma, type_ref); var comma_list_opt = new NonTerminal("comma_list_opt"); comma_list_opt.Rule = MakeStarRule(comma_list_opt, comma); rank_specifier.Rule = "[" + comma_list_opt + "]"; rank_specifiers.Rule = MakePlusRule(rank_specifiers, null, rank_specifier); rank_specifiers_opt.Rule = rank_specifiers.Q(); integral_type.Rule = Symbol("sbyte") | "byte" | "short" | "ushort" | "int" | "uint" | "long" | "ulong" | "char"; //B.2.4. Variables //Quite strange in specs - // variable-reference: // expression // Is that case it would be possible to do the following: // GetMyStuff(out (a+b)); // but MS c# rejects it //B.2.4. Expressions argument.Rule = expression | "ref" + identifier | "out" + identifier; argument_list.Rule = MakePlusRule(argument_list, comma, argument); argument_list_opt.Rule = Empty | argument_list; expression.Rule = conditional_expression | bin_op_expression | typecast_expression | primary_expression; expression_opt.Rule = Empty | expression; expression_list.Rule = MakePlusRule(expression_list, comma, expression); unary_operator.Rule = Symbol("+") | "-" | "!" | "~" | "*"; assignment_operator.Rule = Symbol("=") | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>="; conditional_expression.Rule = expression + qmark + expression + colon + expression; bin_op_expression.Rule = expression + bin_op + expression; typecast_expression.Rule = parenthesized_expression + primary_expression; primary_expression.Rule = literal | unary_operator + primary_expression | parenthesized_expression | member_access | pre_incr_decr_expression | post_incr_decr_expression | object_creation_expression | anonymous_object_creation_expression | typeof_expression | checked_expression | unchecked_expression | default_value_expression | anonymous_method_expression; dim_specifier.Rule = "[" + expression_list + "]"; dim_specifier_opt.Rule = dim_specifier.Q(); literal.Rule = Number | StringLiteral | CharLiteral | "true" | "false" | "null"; parenthesized_expression.Rule = Lpar + expression + Rpar; pre_incr_decr_expression.Rule = incr_or_decr + member_access; post_incr_decr_expression.Rule = member_access + incr_or_decr; //joined invocation_expr and member_access; for member access left the most general variant member_access.Rule = identifier_ext + member_access_segments_opt; member_access_segments_opt.Rule = MakeStarRule(member_access_segments_opt, null, member_access_segment); member_access_segment.Rule = dot + identifier | array_indexer | argument_list_par | type_argument_list; array_indexer.Rule = "[" + expression_list + "]"; argument_list_par.Rule = Lpar + argument_list_opt + Rpar; argument_list_par_opt.Rule = Empty | argument_list_par; list_initializer.Rule = Lbr + elem_initializer_list_ext + Rbr; list_initializer_opt.Rule = list_initializer.Q(); elem_initializer.Rule = initializer_value | identifier + "=" + initializer_value; elem_initializer_list.Rule = MakePlusRule(elem_initializer_list, comma, elem_initializer); elem_initializer_list_ext.Rule = Empty | elem_initializer_list + comma_opt; initializer_value.Rule = expression | list_initializer; //delegate, anon-object, object object_creation_expression.Rule = "new" + qual_name_with_targs + qmark_opt + creation_args + list_initializer_opt; creation_args.Rule = dim_specifier | rank_specifier | argument_list_par; anonymous_object_creation_expression.Rule = "new" + anonymous_object_initializer; anonymous_object_initializer.Rule = Lbr + Rbr | Lbr + member_declarator_list + comma_opt + Rbr; member_declarator.Rule = expression | identifier + "=" + expression; member_declarator_list.Rule = MakePlusRule(member_declarator_list, comma, member_declarator); //typeof typeof_expression.Rule = "typeof" + Lpar + type_ref + Rpar; generic_dimension_specifier_opt.Rule = Empty | "<" + commas_opt + ">"; //checked, unchecked checked_expression.Rule = "checked" + parenthesized_expression; unchecked_expression.Rule = "unchecked" + parenthesized_expression; //default-value default_value_expression.Rule = "default" + Lpar + type_ref + Rpar; //note: we treat ?? as bin-operation, so null-coalesce-expr used in spec as first (condition) component is replaced with expression // we resolve all this expr hierarchies of binary expressions using precedence //anonymous method and lambda - we join explicit and implicit param definitions, making 'type' element optional // TODO: add after-parse check for this anonymous_method_expression.Rule = "delegate" + anonymous_function_signature_opt + block; lambda_expression.Rule = lambda_function_signature + "=>" + anonymous_function_body; lambda_function_signature.Rule = anonymous_function_signature | identifier; anonymous_function_signature.Rule = Lpar + anonymous_function_parameter_list_opt + Rpar; anonymous_function_signature_opt.Rule = anonymous_function_signature.Q(); anonymous_function_parameter_modifier_opt.Rule = Empty | "ref" | "out"; anonymous_function_parameter.Rule = anonymous_function_parameter_modifier_opt + anonymous_function_parameter_decl; anonymous_function_parameter_decl.Rule = identifier | type_ref + identifier; anonymous_function_parameter_list_opt.Rule = MakeStarRule(anonymous_function_parameter_list_opt, comma, anonymous_function_parameter_decl); anonymous_function_body.Rule = expression | block; //we don't use grammar expressions to specify operator precedence, so we combine all these grammar elements together // and define just bin_op_expression. Where to put it? // In spec: non_assignment_expression.Rule = conditional_expression | lambda_expression | query_expression; //I think it's a mistake; there must be additional entry here for arithm expressions, so we put them here. // We also have to add "is" and "as" expressions here, as we don't build entire hierarchy of elements for expressing // precedence (where they appear in original spec); so we put them here bin_op.Rule = Symbol("<") | "||" | "&&" | "|" | "^" | "&" | "==" | "!=" | ">" | "<=" | ">=" | "<<" | ">>" | "+" | "-" | "*" | "/" | "%" | "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "is" | "as" | "??"; //type_check_expression.Rule = expression + "is" + type_ref | expression + "as" + type_ref; //Queries query_expression.Rule = "from"; //B.2.5. Statements statement.Rule = labeled_statement | declaration_statement | embedded_statement; statement.ErrorRule = SyntaxError + semi; //skip all until semicolon statement_list.Rule = MakePlusRule(statement_list, null, statement); statement_list_opt.Rule = Empty | statement_list; //labeled_statement labeled_statement.Rule = identifier + colon + embedded_statement; //declaration_statement declaration_statement.Rule = local_variable_declaration + semi | local_constant_declaration + semi; local_variable_declaration.Rule = local_variable_type + local_variable_declarators; //!!! local_variable_type.Rule = member_access | "var"; // | builtin_type; //to fix the conflict, changing to member-access here local_variable_declarator.Rule = identifier | identifier + "=" + local_variable_initializer; local_variable_declarators.Rule = MakePlusRule(local_variable_declarators, comma, local_variable_declarator); local_variable_initializer.Rule = expression | list_initializer; local_constant_declaration.Rule = "const" + type_ref + constant_declarators; //embedded_statement embedded_statement.Rule = block | semi /*empty_statement*/ | statement_expression + semi | selection_statement | iteration_statement | jump_statement | try_statement | checked_statement | unchecked_statement | lock_statement | using_statement | yield_statement; block.Rule = Lbr + statement_list_opt + Rbr; //selection (if and switch) selection_statement.Rule = if_statement | switch_statement; if_statement.Rule = Symbol("if") + Lpar + expression + Rpar + embedded_statement + else_clause_opt; else_clause_opt.Rule = Empty | PreferShiftHere() + "else" + embedded_statement; switch_statement.Rule = "switch" + parenthesized_expression + Lbr + switch_sections_opt + Rbr; switch_section.Rule = switch_labels + statement_list; switch_sections_opt.Rule = MakeStarRule(switch_sections_opt, null, switch_section); switch_label.Rule = "case" + expression + colon | "default" + colon; switch_labels.Rule = MakePlusRule(switch_labels, null, switch_label); //iteration statements iteration_statement.Rule = while_statement | do_statement | for_statement | foreach_statement; while_statement.Rule = "while" + parenthesized_expression + embedded_statement; do_statement.Rule = "do" + embedded_statement + "while" + parenthesized_expression + semi; for_statement.Rule = "for" + Lpar + for_initializer_opt + semi + for_condition_opt + semi + for_iterator_opt + Rpar + embedded_statement; for_initializer_opt.Rule = Empty | local_variable_declaration | statement_expression_list; for_condition_opt.Rule = Empty | expression; for_iterator_opt.Rule = Empty | statement_expression_list; foreach_statement.Rule = "foreach" + Lpar + local_variable_type + identifier + "in" + expression + Rpar + embedded_statement; //jump-statement jump_statement.Rule = break_statement | continue_statement | goto_statement | return_statement | throw_statement; break_statement.Rule = "break" + semi; continue_statement.Rule = "continue" + semi; goto_statement.Rule = tgoto + identifier + semi | tgoto + "case" + expression + semi | tgoto + "default" + semi; return_statement.Rule = "return" + expression_opt + semi; throw_statement.Rule = "throw" + expression_opt + semi; //try-statement //changed to avoid conflicts; need to check correct ordering of catch/finally clause in after-parse validation try_statement.Rule = "try" + block + try_clauses; try_clause.Rule = catch_clause | finally_clause; try_clauses.Rule = MakePlusRule(try_clauses, null, try_clause); catch_clause.Rule = "catch" + catch_specifier_opt + block; finally_clause.Rule = "finally" + block; catch_specifier_opt.Rule = Empty | Lpar + qual_name_with_targs + identifier_opt + Rpar; identifier_opt.Rule = Empty | identifier; //checked, unchecked, locked, using checked_statement.Rule = "checked" + block; unchecked_statement.Rule = "unchecked" + block; lock_statement.Rule = "lock" + parenthesized_expression + embedded_statement; using_statement.Rule = "using" + Lpar + resource_acquisition + Rpar + embedded_statement; resource_acquisition.Rule = local_variable_declaration | expression; //yield statement yield_statement.Rule = yld + "return" + expression + semi | yld + "break" + semi; //expression statement // expression_statement.Rule = statement_expression + semi; statement_expression.Rule = object_creation_expression | member_access | member_access + assignment_operator + expression | pre_incr_decr_expression | post_incr_decr_expression ; statement_expression_list.Rule = MakePlusRule(statement_expression_list, comma, statement_expression); incr_or_decr_opt.Rule = Empty | Symbol("++") | "--"; incr_or_decr.Rule = Symbol("++") | "--"; //B.2.6. Namespaces this.Root = compilation_unit; compilation_unit.Rule = extern_alias_directives_opt + using_directives_opt + attributes_opt + namespace_declarations_opt; extern_alias_directive.Rule = Symbol("extern") + "alias" + identifier + semi; extern_alias_directives_opt.Rule = MakeStarRule(extern_alias_directives_opt, null, extern_alias_directive); namespace_declaration.Rule = "namespace" + qualified_identifier + namespace_body + semi_opt; namespace_declarations_opt.Rule = MakeStarRule(namespace_declarations_opt, null, namespace_declaration); qualified_identifier.Rule = MakePlusRule(qualified_identifier, dot, identifier); namespace_body.Rule = "{" + extern_alias_directives_opt + using_directives_opt + namespace_member_declarations + "}"; using_directive.Rule = using_alias_directive | using_ns_directive; using_directives.Rule = MakePlusRule(using_directives, null, using_directive); using_directives_opt.Rule = Empty | using_directives; using_alias_directive.Rule = "using" + identifier + "=" + qual_name_with_targs + semi; using_ns_directive.Rule = "using" + qual_name_with_targs + semi; namespace_member_declaration.Rule = namespace_declaration | type_declaration; namespace_member_declarations.Rule = MakePlusRule(namespace_member_declarations, null, namespace_member_declaration); type_declaration.Rule = class_declaration | struct_declaration | interface_declaration | enum_declaration | delegate_declaration; //B.2.7. Classes class_declaration.Rule = member_header + "class" + identifier + type_parameter_list_opt + bases_opt + type_parameter_constraints_clauses_opt + class_body; class_body.Rule = Lbr + member_declaration.Star() + Rbr; bases_opt.Rule = Empty | colon + base_type_list; base_type_list.Rule = MakePlusRule(base_type_list, comma, qual_name_with_targs); //Type parameters type_parameter.Rule = attributes_opt + identifier; type_parameters.Rule = MakePlusRule(type_parameters, comma, type_parameter); type_parameter_list_opt.Rule = Empty | "<" + type_parameters + ">"; type_parameter_constraints_clause.Rule = "where" + type_parameter + colon + type_parameter_constraints; type_parameter_constraints.Rule = MakePlusRule(type_parameter_constraints, comma, type_parameter_constraint); type_parameter_constraints_clauses_opt.Rule = MakeStarRule(type_parameter_constraints_clauses_opt, null, type_parameter_constraints_clause); //Note for post-processing - make sure the order is correct: new() is always last, etc. See p.503 of the spec type_parameter_constraint.Rule = qual_name_with_targs | "class" | "struct" | Symbol("new") + Lpar + Rpar; //Class members //Note: we split operator-declaration into two separate operator elements: bin/unary and conversion operators // to avoid possible ambiguities and conflicts member_declaration.Rule = constant_declaration | field_declaration | method_declaration | property_declaration | event_declaration | indexer_declaration | operator_declaration | conversion_operator_declaration | constructor_declaration | destructor_declaration | type_declaration; member_declarations_opt.Rule = MakeStarRule(member_declarations_opt, null, member_declaration); //Modifiers - see note #1 in Notes.txt file modifier.Rule = Symbol("new") | "public" | "protected" | "internal" | "private" | "static" | "virtual" | "sealed" | "override" | "abstract" | "readonly" | "volatile" | "partial" | "extern"; //!!! modifiers_opt.Rule = MakeStarRule(modifiers_opt, null, modifier); //Joined member header - see note #2 member_header.Rule = attributes_opt + modifiers_opt; constant_declaration.Rule = member_header + "const" + type_ref + constant_declarators + semi; constant_declarator.Rule = identifier + "=" + expression; constant_declarators.Rule = MakePlusRule(constant_declarators, comma, constant_declarator); field_declaration.Rule = member_header + type_ref + variable_declarators + semi; variable_declarator.Rule = identifier | identifier + "=" + elem_initializer; variable_declarators.Rule = MakePlusRule(variable_declarators, comma, variable_declarator); //See note #3 about merging type_parameter_list into type_arguments of the preceding qual_name. method_declaration.Rule = member_header + type_ref + qual_name_with_targs // + type_parameter_list.Q() + formal_parameter_list_par + type_parameter_constraints_clauses_opt + method_body; formal_parameter_list.Rule = fixed_parameters | fixed_parameters + comma + parameter_array | parameter_array; formal_parameter_list_par.Rule = Lpar + Rpar | Lpar + formal_parameter_list + Rpar; fixed_parameter.Rule = attributes_opt + parameter_modifier_opt + type_ref + identifier; fixed_parameters.Rule = MakePlusRule(fixed_parameters, comma, fixed_parameter); parameter_modifier_opt.Rule = Empty | "ref" | "out" | "this"; parameter_array.Rule = attributes_opt + "params" + type_ref + /*"[" + "]" + */ identifier; method_body.Rule = block | semi; // See note #4 about member-name //TODO: add after-parse validation that no more than one accessor of each type is there. property_declaration.Rule = member_header + type_ref + qual_name_with_targs/*member-name*/ + Lbr + accessor_declarations + Rbr; accessor_declaration.Rule = attributes_opt + accessor_modifier_opt + accessor_name + block; accessor_declarations.Rule = MakePlusRule(accessor_declarations, null, accessor_declaration); accessor_name.Rule = Symbol("get") | "set"; accessor_modifier_opt.Rule = Empty | "protected" | "internal" | "private" | Symbol("protected") + "internal" | Symbol("internal") + "protected"; event_declaration.Rule = member_header + "event" + type_ref + event_body; event_body.Rule = variable_declarators + semi | qual_name_with_targs + Lbr + event_accessor_declarations + Rbr; event_accessor_declarations.Rule = add_accessor_declaration + remove_accessor_declaration | remove_accessor_declaration + add_accessor_declaration; add_accessor_declaration.Rule = attributes_opt + "add" + block; remove_accessor_declaration.Rule = attributes_opt + "remove" + block; //indexer indexer_declaration.Rule = member_header + type_ref + indexer_name + "[" + formal_parameter_list + "]" + Lbr + accessor_declarations + Rbr; indexer_name.Rule = "this" | qual_name_with_targs + dot + "this"; //operator // note: difference with specs - we separate unary/binary operators from conversion operator, // and join binary and unary operator definitions, see note #5 operator_declaration.Rule = member_header + type_ref + "operator" + overloadable_operator + Lpar + operator_parameters + Rpar + block; overloadable_operator.Rule = Symbol("+") | "-" | "!" | "~" | "++" | "--" | "true" | "false" //unary operators | "*" | "/" | "%" | "&" | "|" | "^" | "<<" | ">>" | "==" | "!=" | ">" | "<" | ">=" | "<="; operator_parameters.Rule = operator_parameter | operator_parameter + comma + operator_parameter; operator_parameter.Rule = type_ref + identifier; conversion_operator_declaration.Rule = member_header + conversion_operator_kind + "operator" + type_ref + Lpar + operator_parameter + Rpar + block; conversion_operator_kind.Rule = Symbol("implicit") | "explicit"; //constructor - also covers static constructor; the only difference is the word static constructor_declaration.Rule = member_header + identifier + formal_parameter_list_par + constructor_initializer_opt + block; constructor_initializer_opt.Rule = Empty | colon + constructor_base + Lpar + argument_list_opt + Rpar; constructor_base.Rule = Symbol("this") | "base"; destructor_declaration.Rule = member_header + // changed from Symbol("extern").Q() "~" + identifier + Lpar + Rpar + block; //B.2.8 struct_declaration.Rule = member_header + "struct" + identifier + type_parameter_list_opt + bases_opt + type_parameter_constraints_clauses_opt + struct_body; struct_body.Rule = Lbr + member_declarations_opt + Rbr; //B.2.9. Arrays //B.2.10 Interface interface_declaration.Rule = member_header + "interface" + identifier + type_parameter_list_opt + bases_opt + type_parameter_constraints_clauses_opt + interface_body; interface_body.Rule = Lbr + interface_member_declarations + Rbr; interface_member_declaration.Rule = interface_method_declaration | interface_property_declaration | interface_event_declaration | interface_indexer_declaration; interface_member_declarations.Rule = MakePlusRule(interface_member_declarations, null, interface_member_declaration); interface_method_declaration.Rule = attributes_opt + new_opt + type_ref + identifier + type_parameter_list_opt + formal_parameter_list_par + type_parameter_constraints_clauses_opt + semi; //NOte: changing type to type_ref to fix the conflict //Note: add after-parse validation that no more than one accessor of each type is there. interface_property_declaration.Rule = attributes_opt + new_opt + type_ref + identifier + Lbr + interface_accessors + Rbr; interface_accessor.Rule = attributes_opt + accessor_name + semi; interface_accessors.Rule = MakePlusRule(interface_accessors, null, interface_accessor); interface_event_declaration.Rule = attributes_opt + new_opt + "event" + type_ref + identifier; interface_indexer_declaration.Rule = attributes_opt + new_opt + type_ref + "this" + "[" + formal_parameter_list + "]" + Lbr + interface_accessors + Rbr; new_opt.Rule = Empty | "new"; //B.2.11 Enums enum_declaration.Rule = member_header + "enum" + identifier + enum_base_opt + Lbr + enum_body + Rbr + semi_opt; enum_base_opt.Rule = Empty | colon + integral_type; enum_body.Rule = Empty | enum_member_declarations + comma_opt; enum_member_declaration.Rule = attributes_opt + identifier | attributes_opt + identifier + "=" + expression; enum_member_declarations.Rule = MakePlusRule(enum_member_declarations, comma, enum_member_declaration); //B.2.12 Delegates delegate_declaration.Rule = member_header + "delegate" + type_ref + identifier + type_parameter_list_opt + formal_parameter_list_par + type_parameter_constraints_clauses_opt + semi; //B.2.13. Attributes attributes_opt.Rule = MakeStarRule(attributes_opt, null, attribute_section); attribute_section.Rule = "[" + attribute_target_specifier_opt + attribute_list + comma_opt + "]"; attribute_list.Rule = MakePlusRule(attribute_list, comma, attribute); attribute.Rule = qual_name_with_targs + attribute_arguments_par_opt; attribute_target_specifier_opt.Rule = Empty | attribute_target + colon; attribute_target.Rule = Symbol("field") | "event" | "method" | "param" | "property" | "return" | "type"; attribute_arguments_par_opt.Rule = Empty | Lpar + attribute_arguments_opt + Rpar; attribute_arguments_opt.Rule = MakeStarRule(attribute_arguments_opt, comma, attr_arg); attr_arg.Rule = identifier + "=" + expression | expression; }
public SqlGrammar() { //Terminals var comment = new CommentTerminal("comment", "/*", "*/"); var lineComment = new CommentTerminal("line_comment", "--", "\n", "\r\n"); NonGrammarTerminals.Add(comment); NonGrammarTerminals.Add(lineComment); var number = new NumberLiteral("number"); var string_literal = new StringLiteral("string", "'", StringFlags.AllowsDoubledQuote); var name = new IdentifierTerminal("name"); var name_ext = TerminalFactory.CreateSqlExtIdentifier("name_ext"); var comma = Symbol(","); var dot = Symbol("."); var CREATE = Symbol("CREATE"); var NULL = Symbol("NULL"); var NOT = Symbol("NOT"); var UNIQUE = Symbol("UNIQUE"); var WITH = Symbol("WITH"); var TABLE = Symbol("TABLE"); var ALTER = Symbol("ALTER"); var ADD = Symbol("ADD"); var COLUMN = Symbol("COLUMN"); var DROP = Symbol("DROP"); var CONSTRAINT = Symbol("CONSTRAINT"); var INDEX = Symbol("INDEX"); var ON = Symbol("ON"); var KEY = Symbol("KEY"); var PRIMARY = Symbol("PRIMARY"); var INSERT = Symbol("INSERT"); var INTO = Symbol("INTO"); var UPDATE = Symbol("UPDATE"); var SET = Symbol("SET"); var VALUES = Symbol("VALUES"); var DELETE = Symbol("DELETE"); var SELECT = Symbol("SELECT"); var FROM = Symbol("FROM"); var AS = Symbol("AS"); var COUNT = Symbol("COUNT"); var JOIN = Symbol("JOIN"); var BY = Symbol("BY"); //Non-terminals var Id = new NonTerminal("Id"); var Id_simple = new NonTerminal("id_simple"); var stmt = new NonTerminal("stmt"); var createTableStmt = new NonTerminal("createTableStmt"); var createIndexStmt = new NonTerminal("createIndexStmt"); var alterStmt = new NonTerminal("alterStmt"); var dropTableStmt = new NonTerminal("dropTableStmt"); var dropIndexStmt = new NonTerminal("dropIndexStmt"); var selectStmt = new NonTerminal("selectStmt"); var insertStmt = new NonTerminal("insertStmt"); var updateStmt = new NonTerminal("updateStmt"); var deleteStmt = new NonTerminal("deleteStmt"); var fieldDef = new NonTerminal("fieldDef"); var fieldDefList = new NonTerminal("fieldDefList"); var nullSpecOpt = new NonTerminal("nullSpecOpt"); var typeName = new NonTerminal("typeName"); var typeSpec = new NonTerminal("typeSpec"); var typeParamsOpt = new NonTerminal("typeParams"); var constraintDef = new NonTerminal("constraintDef"); var constraintListOpt = new NonTerminal("constraintListOpt"); var constraintTypeOpt = new NonTerminal("constraintTypeOpt"); var idlist = new NonTerminal("idlist"); var idlistPar = new NonTerminal("idlistPar"); var uniqueOpt = new NonTerminal("uniqueOpt"); var orderList = new NonTerminal("orderList"); var orderMember = new NonTerminal("orderMember"); var orderDirOpt = new NonTerminal("orderDirOpt"); var withClauseOpt = new NonTerminal("withClauseOpt"); var alterCmd = new NonTerminal("alterCmd"); var insertData = new NonTerminal("insertData"); var intoOpt = new NonTerminal("intoOpt"); var assignList = new NonTerminal("assignList"); var whereClauseOpt = new NonTerminal("whereClauseOpt"); var assignment = new NonTerminal("assignment"); var expression = new NonTerminal("expression"); var exprList = new NonTerminal("exprList"); var selRestrOpt = new NonTerminal("selRestrOpt"); var selList = new NonTerminal("selList"); var intoClauseOpt = new NonTerminal("intoClauseOpt"); var fromClauseOpt = new NonTerminal("fromClauseOpt"); var groupClauseOpt = new NonTerminal("groupClauseOpt"); var havingClauseOpt = new NonTerminal("havingClauseOpt"); var orderClauseOpt = new NonTerminal("orderClauseOpt"); var columnItemList = new NonTerminal("columnItemList"); var columnItem = new NonTerminal("columnItem"); var columnSource = new NonTerminal("columnSource"); var asOpt = new NonTerminal("asOpt"); var aliasOpt = new NonTerminal("aliasOpt"); var aggregate = new NonTerminal("aggregate"); var aggregateArg = new NonTerminal("aggregateArg"); var aggregateName = new NonTerminal("aggregateName"); var tuple = new NonTerminal("tuple"); var joinChainOpt = new NonTerminal("joinChainOpt"); var joinKindOpt = new NonTerminal("joinKindOpt"); var term = new NonTerminal("term"); var unExpr = new NonTerminal("unExpr"); var unOp = new NonTerminal("unOp"); var binExpr = new NonTerminal("binExpr"); var binOp = new NonTerminal("binOp"); var betweenExpr = new NonTerminal("betweenExpr"); var inExpr = new NonTerminal("inExpr"); var parSelectStmt = new NonTerminal("parSelectStmt"); var notOpt = new NonTerminal("notOpt"); var funCall = new NonTerminal("funCall"); var stmtLine = new NonTerminal("stmtLine"); var semiOpt = new NonTerminal("semiOpt"); var stmtList = new NonTerminal("stmtList"); var funArgs = new NonTerminal("funArgs"); var inStmt = new NonTerminal("inStmt"); //BNF Rules this.Root = stmtList; stmtLine.Rule = stmt + semiOpt; semiOpt.Rule = Empty | ";"; stmtList.Rule = MakePlusRule(stmtList, stmtLine); //ID Id_simple.Rule = name | name_ext; Id.Rule = MakePlusRule(Id, dot, Id_simple); stmt.Rule = createTableStmt | createIndexStmt | alterStmt | dropTableStmt | dropIndexStmt | selectStmt | insertStmt | updateStmt | deleteStmt | "GO" ; //Create table createTableStmt.Rule = CREATE + TABLE + Id + "(" + fieldDefList + ")" + constraintListOpt; fieldDefList.Rule = MakePlusRule(fieldDefList, comma, fieldDef); fieldDef.Rule = Id + typeName + typeParamsOpt + nullSpecOpt; nullSpecOpt.Rule = NULL | NOT + NULL | Empty; typeName.Rule = Symbol("BIT") | "DATE" | "TIME" | "TIMESTAMP" | "DECIMAL" | "REAL" | "FLOAT" | "SMALLINT" | "INTEGER" | "INTERVAL" | "CHARACTER" // MS SQL types: | "DATETIME" | "INT" | "DOUBLE" | "CHAR" | "NCHAR" | "VARCHAR" | "NVARCHAR" | "IMAGE" | "TEXT" | "NTEXT"; typeParamsOpt.Rule = "(" + number + ")" | "(" + number + comma + number + ")" | Empty; constraintDef.Rule = CONSTRAINT + Id + constraintTypeOpt; constraintListOpt.Rule = MakeStarRule(constraintListOpt, constraintDef ); constraintTypeOpt.Rule = PRIMARY + KEY + idlistPar | UNIQUE + idlistPar | NOT + NULL + idlistPar | "Foreign" + KEY + idlistPar + "References" + Id + idlistPar; idlistPar.Rule = "(" + idlist + ")"; idlist.Rule = MakePlusRule(idlist, comma, Id); //Create Index createIndexStmt.Rule = CREATE + uniqueOpt + INDEX + Id + ON + Id + orderList + withClauseOpt; uniqueOpt.Rule = Empty | UNIQUE; orderList.Rule = MakePlusRule(orderList, comma, orderMember); orderMember.Rule = Id + orderDirOpt; orderDirOpt.Rule = Empty | "ASC" | "DESC"; withClauseOpt.Rule = Empty | WITH + PRIMARY | WITH + "Disallow" + NULL | WITH + "Ignore" + NULL; //Alter alterStmt.Rule = ALTER + TABLE + Id + alterCmd; alterCmd.Rule = ADD + COLUMN + fieldDefList + constraintListOpt | ADD + constraintDef | DROP + COLUMN + Id | DROP + CONSTRAINT + Id; //Drop stmts dropTableStmt.Rule = DROP + TABLE + Id; dropIndexStmt.Rule = DROP + INDEX + Id + ON + Id; //Insert stmt insertStmt.Rule = INSERT + intoOpt + Id + idlistPar + insertData; insertData.Rule = selectStmt | VALUES + "(" + exprList + ")"; intoOpt.Rule = Empty | INTO; //Into is optional in MSSQL //Update stmt updateStmt.Rule = UPDATE + Id + SET + assignList + whereClauseOpt; assignList.Rule = MakePlusRule(assignList, comma, assignment); assignment.Rule = Id + "=" + expression; //Delete stmt deleteStmt.Rule = DELETE + FROM + Id + whereClauseOpt; //Select stmt selectStmt.Rule = SELECT + selRestrOpt + selList + intoClauseOpt + fromClauseOpt + whereClauseOpt + groupClauseOpt + havingClauseOpt + orderClauseOpt; selRestrOpt.Rule = Empty | "ALL" | "DISTINCT"; selList.Rule = columnItemList | "*"; columnItemList.Rule = MakePlusRule(columnItemList, comma, columnItem); columnItem.Rule = columnSource + aliasOpt; aliasOpt.Rule = Empty | asOpt + Id; asOpt.Rule = Empty | AS; columnSource.Rule = aggregate | Id; aggregate.Rule = aggregateName + "(" + aggregateArg + ")"; aggregateArg.Rule = expression | "*"; aggregateName.Rule = COUNT | "Avg" | "Min" | "Max" | "StDev" | "StDevP" | "Sum" | "Var" | "VarP"; intoClauseOpt.Rule = Empty | INTO + Id; fromClauseOpt.Rule = Empty | FROM + idlist + joinChainOpt; joinChainOpt.Rule = Empty | joinKindOpt + JOIN + idlist + ON + Id + "=" + Id; joinKindOpt.Rule = Empty | "INNER" | "LEFT" | "RIGHT"; whereClauseOpt.Rule = Empty | "WHERE" + expression; groupClauseOpt.Rule = Empty | "GROUP" + BY + idlist; havingClauseOpt.Rule = Empty | "HAVING" + expression; orderClauseOpt.Rule = Empty | "ORDER" + BY + orderList; //Expression exprList.Rule = MakePlusRule(exprList, comma, expression); expression.Rule = term | unExpr | binExpr;// | betweenExpr; //-- BETWEEN doesn't work - yet; brings a few parsing conflicts term.Rule = Id | string_literal | number | funCall | tuple | parSelectStmt;// | inStmt; tuple.Rule = "(" + exprList + ")"; parSelectStmt.Rule = "(" + selectStmt + ")"; unExpr.Rule = unOp + term; unOp.Rule = NOT | "+" | "-" | "~"; binExpr.Rule = expression + binOp + expression; binOp.Rule = Symbol("+") | "-" | "*" | "/" | "%" //arithmetic | "&" | "|" | "^" //bit | "=" | ">" | "<" | ">=" | "<=" | "<>" | "!=" | "!<" | "!>" | "AND" | "OR" | "LIKE" | NOT + "LIKE" | "IN" | NOT + "IN" ; betweenExpr.Rule = expression + notOpt + "BETWEEN" + expression + "AND" + expression; notOpt.Rule = Empty | NOT; //funCall covers some psedo-operators and special forms like ANY(...), SOME(...), ALL(...), EXISTS(...), IN(...) funCall.Rule = name + "(" + funArgs + ")"; funArgs.Rule = selectStmt | exprList; inStmt.Rule = expression + "IN" + "(" + exprList + ")"; //Operators this.CaseSensitive = false; RegisterOperators(10, "*", "/", "%"); RegisterOperators(9, "+", "-"); RegisterOperators(8, "=" , ">" , "<" , ">=" , "<=" , "<>" , "!=" , "!<" , "!>"); RegisterOperators(7, "^", "&", "|"); RegisterOperators(6, "NOT"); RegisterOperators(5, "AND"); RegisterOperators(4, "OR", "LIKE", "IN"); RegisterPunctuation(",", "(", ")"); RegisterPunctuation(semiOpt); base.MarkTransient(stmt, Id_simple, asOpt, aliasOpt, stmtLine); AddKeywords("SELECT", "CREATE", "ALTER", "UPDATE", "INSERT", "DELETE", "FROM", "WHERE", "GROUP", "ORDER", "BY", "INNER", "LEFT", "RIGHT", "JOIN", "ON"); }
// It is loosely based on R6RS specs. // See Grammar Errors tab in GrammarExplorer for remaining conflicts. public SchemeGrammar() { #region Terminals ConstantTerminal Constant = new ConstantTerminal("Constant"); Constant.Add("#T", 1); Constant.Add("#t", 1); Constant.Add("#F", null); Constant.Add("#f", null); Constant.Add("'()", null); Constant.Add(@"#\nul", '\u0000'); Constant.Add(@"#\alarm", '\u0007'); Constant.Add(@"#\backspace", '\b'); Constant.Add(@"#\tab", '\t'); Constant.Add(@"#\linefeed", '\n'); Constant.Add(@"#\vtab", '\v'); Constant.Add(@"#\page", '\f'); Constant.Add(@"#\return", '\r'); Constant.Add(@"#\esc", '\u001B'); Constant.Add(@"#\space", ' '); Constant.Add(@"#\delete", '\u007F'); // TODO: build SchemeCharLiteral // the following is nonsense, just to put something there var charLiteral = new StringLiteral("Char", "'", StringFlags.None); var stringLiteral = new StringLiteral("String", "\"", StringFlags.AllowsAllEscapes); //Identifiers. Note: added "-", just to allow IDs starting with "->" var SimpleIdentifier = new IdentifierTerminal("SimpleIdentifier", "_+-*/.@?!<>=", "_+-*/.@?!<>=$%&:^~"); // name extraChars extraFirstChars var Number = TerminalFactory.CreateSchemeNumber("Number"); var Byte = new NumberLiteral("Byte", NumberFlags.IntOnly); //Comments Terminal Comment = new CommentTerminal("Comment", "#|", "|#"); Terminal LineComment = new CommentTerminal("LineComment", ";", "\n"); NonGrammarTerminals.Add(Comment); //add comments explicitly to this list as it is not reachable from Root NonGrammarTerminals.Add(LineComment); #endregion #region NonTerminals var Module = new NonTerminal("Module"); var Library = new NonTerminal("Library"); var LibraryList = new NonTerminal("Library+"); var Script = new NonTerminal("Script"); var Abbreviation = new NonTerminal("Abbreviation"); var Vector = new NonTerminal("Vector"); var ByteList = new NonTerminal("ByteList"); var ByteVector = new NonTerminal("ByteVector"); var Datum = new NonTerminal("Datum"); //Datum in R6RS terms var DatumOpt = new NonTerminal("DatumOpt"); //Datum in R6RS terms var DatumList = new NonTerminal("Datum+", typeof(StatementListNode)); var DatumListOpt = new NonTerminal("Datum*", typeof(StatementListNode)); var Statement = new NonTerminal("Statement"); var Atom = new NonTerminal("Atom"); var CompoundDatum = new NonTerminal("CompoundDatum"); var AbbrevPrefix = new NonTerminal("AbbrevPrefix"); var LibraryName = new NonTerminal("LibraryName"); var LibraryBody = new NonTerminal("LibraryBody"); var ImportSection = new NonTerminal("ImportSection"); var ExportSection = new NonTerminal("ExportSection"); var ImportSpec = new NonTerminal("ImportSpec"); var ImportSpecList = new NonTerminal("ImportSpecList"); var ExportSpec = new NonTerminal("ExportSpec"); var ExportSpecList = new NonTerminal("ExportSpecList"); var LP = new NonTerminal("LP"); //"(" or "[" var RP = new NonTerminal("RP"); // ")" or "]" var Identifier = new NonTerminal("Identifier", typeof(VarRefNode)); var IdentifierList = new NonTerminal("IdentifierList"); var IdentifierListOpt = new NonTerminal("IdentifierListOpt"); var PeculiarIdentifier = new NonTerminal("PeculiarIdentifier"); var LibraryVersion = new NonTerminal("LibraryVersion"); var VersionListOpt = new NonTerminal("VersionListOpt"); var FunctionCall = new NonTerminal("FunctionCall", CreateFunctionCallNode); var FunctionRef = new NonTerminal("FunctionRef"); var SpecialForm = new NonTerminal("SpecialForm"); var DefineVarForm = new NonTerminal("DefineVarForm", CreateDefineVarNode); var DefineFunForm = new NonTerminal("DefineFunForm", CreateDefineFunNode); var LambdaForm = new NonTerminal("LambdaForm", CreateLambdaNode); var IfForm = new NonTerminal("IfForm", CreateIfThenElseNode); var CondForm = new NonTerminal("CondForm", CreateCondFormNode); var CondClause = new NonTerminal("CondClause", CreateCondClauseNode); var CondClauseList = new NonTerminal("CondClauseList"); var CondElseOpt = new NonTerminal("CondElseOpt"); var BeginForm = new NonTerminal("BeginForm", CreateBeginNode); var LetForm = new NonTerminal("LetForm"); //not implemented var LetRecForm = new NonTerminal("LetRecForm"); //not implemented var LetPair = new NonTerminal("LetPair"); var LetPairList = new NonTerminal("LetPairList"); #endregion #region Rules // // Using optional elements in Scheme grammar brings some nasty conflicts - by default the parser selects "shift" over reduce // which leads to failure to parse simple programs without libraries and export/import sections. // This trouble comes from that the fact that Scheme has soooooo many parenthesis. Therefore, using a single next symbol // as a lookahead (as it happens in LALR parsing) doesn't help much - the next symbol is almost always a parenthesis, // not some meaningful symbol. That's why in the following expressions I had to use explicit listing of variants, // instead of simply marking some elements as optional (see Module, Script, LibraryBody elements) - this clears the conflicts // but would make node construction more difficult. base.Root = Module; LP.Rule = Symbol("(") | "["; //R6RS allows mix & match () and [] RP.Rule = Symbol(")") | "]"; // Module.Rule = LibraryListOpt + Script; -- this brings conflicts Module.Rule = LibraryList + Script | Script; LibraryList.Rule = MakePlusRule(LibraryList, Library); Script.Rule = ImportSection + DatumList | DatumList; //Library // the following doesn't work - brings conflicts that incorrectly resolved by default shifting //Library.Rule = LP + "library" + LibraryName + ExportSectionOpt + ImportSectionOpt + DatumListOpt + RP; Library.Rule = LP + "library" + LibraryName + LibraryBody + RP; //Note - we should be using DatumListOpt, but that brings 2 conflicts, so for now it is just DatumList //Note that the following style of BNF expressions is strongly discouraged - all productions should be of the same length, // so that the process of mapping child nodes to parent's properties is straightforward. LibraryBody.Rule = ExportSection + ImportSection + DatumList | ExportSection + DatumList | ImportSection + DatumList | DatumList; LibraryName.Rule = LP + IdentifierList + LibraryVersion.Q() + RP; LibraryVersion.Rule = LP + VersionListOpt + RP; //zero or more subversion numbers VersionListOpt.Rule = MakeStarRule(VersionListOpt, Number); ExportSection.Rule = LP + "export" + ExportSpecList + RP; ImportSection.Rule = LP + "import" + ImportSpecList + RP; ExportSpecList.Rule = MakePlusRule(ExportSpecList, ExportSpec); ImportSpecList.Rule = MakePlusRule(ImportSpecList, ImportSpec); ExportSpec.Rule = Identifier | LP + "rename" + LP + Identifier + Identifier + RP + RP; ImportSpec.Rule = LP + Identifier + RP; // - much more complex in R6RS //Datum Datum.Rule = Atom | CompoundDatum; DatumOpt.Rule = Empty | Datum; DatumList.Rule = MakePlusRule(DatumList, Datum); DatumListOpt.Rule = MakeStarRule(DatumListOpt, Datum); Atom.Rule = Number | Identifier | stringLiteral | Constant | charLiteral | "."; CompoundDatum.Rule = Statement | Abbreviation | Vector | ByteVector; Identifier.Rule = SimpleIdentifier | PeculiarIdentifier; IdentifierList.Rule = MakePlusRule(IdentifierList, Identifier); IdentifierListOpt.Rule = MakeStarRule(IdentifierListOpt, Identifier); //TODO: create PeculiarIdentifier custom terminal instead of var // or just custom SchemeIdentifier terminal PeculiarIdentifier.Rule = Symbol("+") | "-" | "..."; // |"->" + subsequent; (should be!) Abbreviation.Rule = AbbrevPrefix + Datum; AbbrevPrefix.Rule = Symbol("'") | "`" | ",@" | "," | "#'" | "#`" | "#,@" | "#,"; Vector.Rule = "#(" + DatumListOpt + ")"; ByteVector.Rule = "#vu8(" + ByteList + ")"; ByteList.Rule = MakeStarRule(ByteList, Byte); Statement.Rule = FunctionCall | SpecialForm; FunctionCall.Rule = LP + FunctionRef + DatumListOpt + RP; FunctionRef.Rule = Identifier | Statement; SpecialForm.Rule = DefineVarForm | DefineFunForm | LambdaForm | IfForm | CondForm | BeginForm | LetForm | LetRecForm; DefineVarForm.Rule = LP + "define" + Identifier + Datum + RP; DefineFunForm.Rule = LP + "define" + LP + Identifier + IdentifierListOpt + RP + DatumList + RP; LambdaForm.Rule = LP + "lambda" + LP + IdentifierListOpt + RP + DatumList + RP; IfForm.Rule = LP + "if" + Datum + Datum + DatumOpt + RP; CondForm.Rule = LP + "cond" + CondClauseList + CondElseOpt + RP; CondClauseList.Rule = MakePlusRule(CondClauseList, CondClause); CondClause.Rule = LP + Datum + DatumList + RP; CondElseOpt.Rule = Empty | LP + "else" + DatumList + RP; LetForm.Rule = LP + "let" + LP + LetPairList + RP + DatumList + RP; LetRecForm.Rule = LP + "letrec" + LP + LetPairList + RP + DatumList + RP; BeginForm.Rule = LP + "begin" + DatumList + RP; LetPairList.Rule = MakePlusRule(LetPairList, LetPair); LetPair.Rule = LP + Identifier + Datum + RP; #endregion //Register brace pairs RegisterBracePair("(", ")"); RegisterBracePair("[", "]"); RegisterPunctuation(LP, RP); //Filters and other stuff BraceMatchFilter filter = new BraceMatchFilter(); TokenFilters.Add(filter); //Scheme is tail-recursive language base.LanguageFlags = LanguageFlags.BubbleNodes | LanguageFlags.TailRecursive | LanguageFlags.SupportsInterpreter | LanguageFlags.SupportsConsole; //keywords - just for colorizer base.AddKeywords("define", "lambda", "cond", "if", "begin", "let"); }