Esempio n. 1
0
        public GWBasicGrammar() : base(false)  // BASIC is not case sensitive...
        {
            this.GrammarComments = "This grammar uses one new Irony feature - Scanner-Parser link. Parser helps Scanner to disambiguate " +
                                   "similar but different token types when more than one terminal matches the current input char.\r\n" +
                                   "See comments in GwBasicGrammar.cs file.";

            /*
             * Scanner-Parser link.
             * The grammar defines 3 terminals for numbers: number, lineNumber and fileNumber. All three return decimal
             * digits in GetFirsts() method. So when current input is a digit, the scanner has 3 potential candidate terminals
             * to match the input. However, because each of the 3 terminals can appear in specific "places" in grammar,
             * the parser is able to assist scanner to pick the correct terminal, depending on the current parser state.
             * The disambiguation happens in Scanner.SelectTerminals method. When the terminal list for current input char
             * has more than 1 terminal, the scanner code gets the current parser state from core parser (through compilerContext),
             * and then checks the terminals agains the ExpectedTerms set in the parser state.
             * As you might see in Grammar Explorer, the conflict is resolved successfully.
             */

            //Terminals
            var lineNumber = new NumberLiteral("LINE_NUMBER", NumberOptions.IntOnly);
            var fileNumber = new NumberLiteral("FILE_NUMBER", NumberOptions.IntOnly);

            var number = new NumberLiteral("NUMBER", NumberOptions.AllowStartEndDot);

            //ints that are too long for int32 are converted to int64
            number.DefaultIntTypes = new TypeCode[] { TypeCode.Int32, TypeCode.Int64 };
            number.AddExponentSymbols("eE", TypeCode.Single);
            number.AddExponentSymbols("dD", TypeCode.Double);
            number.AddSuffix("!", TypeCode.Single);
            number.AddSuffix("#", TypeCode.Double);

            var variable = new IdentifierTerminal("Identifier");

            variable.AddSuffix("$", TypeCode.String);
            variable.AddSuffix("%", TypeCode.Int32);
            variable.AddSuffix("!", TypeCode.Single);
            variable.AddSuffix("#", TypeCode.Double);

            var stringLiteral = new StringLiteral("STRING", "\"", StringOptions.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 line_cont        = new LineContinuationTerminal("LineContinuation", "_");
            var comma            = ToTerm(",", "comma");
            var colon            = ToTerm(":", "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 | "#";

            // Non-terminals
            var PROGRAM                   = new NonTerminal("PROGRAM");
            var LINE                      = new NonTerminal("LINE");
            var LINE_CONTENT_OPT          = new NonTerminal("LINE_CONTENT_OPT");
            var COMMENT_OPT               = new NonTerminal("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", "operator");
            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 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");
            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;

            // BNF Rules
            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_OPT + COMMENT_OPT + NewLine | SyntaxError + NewLine;
            LINE.NodeCaptionTemplate = "Line #{0}";

            // A statement list is 1 or more statements separated by the ':' character
            LINE_CONTENT_OPT.Rule = Empty | IF_STMT | STATEMENT_LIST;
            STATEMENT_LIST.Rule   = MakePlusRule(STATEMENT_LIST, colon, STATEMENT);
            COMMENT_OPT.Rule      = short_comment | 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        = ToTerm("o") | "i" | "a" | "output" | "input" | "append";
            CLOSE_STMT.Rule            = "close" + pound_opt + fileNumber;
            LINE_INPUT_STMT.Rule       = ToTerm("line") + "input" + semi_opt + stringLiteral + ";" + VARIABLE_OR_FUNCTION_EXPR;
            LINE_INPUT_POUND_STMT.Rule = ToTerm("line") + "input" + ToTerm("#") + 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_STMT;

            //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 + (ToTerm("goto") | "gosub") + LINE_NUMBERS;
            LINE_NUMBERS.Rule   = MakePlusRule(LINE_NUMBERS, comma, lineNumber);
            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     = ToTerm("clear") + comma + (Empty | number) + (Empty | comma + number) | "clear" + number | "clear";
            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        = ToTerm("-") | "+";

            //Inject PreferShift hint here to explicitly set shift as preferred action. Suppresses warning message about conflict.
            //The conflict arises from PRINT statement, when there may be ambigous interpretations for expression like
            //  PRINT F (X) -- either function call or identifier followed by expression
            FUN_CALL.Rule = variable + PreferShiftHere() + "(" + ARG_LIST + ")";
            VARIABLE_OR_FUNCTION_EXPR.Rule = variable | FUN_CALL;

            BINARY_OP.Rule = ToTerm("+") | "^" | "-" | "*" | "/" | "=" | "<=" | ">=" | "<" | ">" | "<>" | "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, 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);


            //Punctuation and Transient elements
            MarkPunctuation("(", ")", ",");
            MarkTransient(EXPR, STATEMENT, LINE_CONTENT_OPT, VARIABLE_OR_FUNCTION_EXPR, COMMENT_OPT);
            NonGrammarTerminals.Add(line_cont);

            this.LanguageFlags = LanguageFlags.NewLineBeforeEOF;

            lineNumber.ValidateToken += identifier_ValidateToken;
        }
Esempio n. 2
0
 // About exponent symbols, extract from R6RS:
 //  ... representations of number objects may be written with an exponent marker that indicates the desired precision 
 // of the inexact representation. The letters s, f, d, and l specify the use of short, single, double, and long precision, respectively.
 // ...
 // In addition, the exponent marker e specifies the default precision for the implementation. The default precision 
 //  has at least as much precision as double, but implementations may wish to allow this default to be set by the user.
 public static NumberLiteral CreateSchemeNumber(string name) {
   NumberLiteral term = new NumberLiteral(name);
   term.DefaultIntTypes = new TypeCode[] { TypeCode.Int32, TypeCode.Int64, NumberLiteral.TypeCodeBigInt };
   term.DefaultFloatType = TypeCode.Double; // it is default
   term.AddExponentSymbols("eE", TypeCode.Double); //default precision for platform, double 
   term.AddExponentSymbols("sSfF", TypeCode.Single); 
   term.AddExponentSymbols("dDlL", TypeCode.Double); 
   term.AddPrefix("#b", NumberOptions.Binary);
   term.AddPrefix("#o", NumberOptions.Octal);
   term.AddPrefix("#x", NumberOptions.Hex);
   term.AddPrefix("#d", NumberOptions.None);
   term.AddPrefix("#i", NumberOptions.None); // inexact prefix, has no effect
   term.AddPrefix("#e", NumberOptions.None); // exact prefix, has no effect
   term.AddSuffix("J", NumberLiteral.TypeCodeImaginary);
   return term;
 }
Esempio n. 3
0
        public T3000Grammar() :
            base(caseSensitive: true) //Changed, Control Basic is Case Sensitive: SET-PRINTER vs Set-Printer
        {
            // 1. Terminals

            //Comentarios
            CommentTerminal Comment = new CommentTerminal("Comment", "REM ", "\n", "\r\n");


            var Number = new NumberLiteral("Number", NumberOptions.AllowStartEndDot | NumberOptions.AllowSign);

            Number.DefaultIntTypes  = new TypeCode[] { TypeCode.Int32, TypeCode.Int64 };
            Number.DefaultFloatType = TypeCode.Single;
            Number.AddExponentSymbols("E", TypeCode.Double);
            Number.AddExponentSymbols("E-", TypeCode.Double);
            Number.Priority = 20;


            //string MyNumberLiteral = "(\\-?\\d+)\\.?\\d+(E\\-|E\\+|E|\\d+)\\d+";
            //var Number = new RegexBasedTerminal("MyNumber", MyNumberLiteral);
            //Number.Priority = 20;


            var IntegerNumber = new NumberLiteral("IntegerNumber", NumberOptions.IntOnly);

            IntegerNumber.Priority = 10;

            var LineNumber = new NumberLiteral("LineNumber", NumberOptions.IntOnly);

            LineNumber.Priority = 11;

            //var Space = new RegexBasedTerminal("Space", "\\s+");

            //var AlarmMessage = new RegexBasedTerminal("AlarmMessage", "(\\w| |\\.|-|,|;|:|!|\\?|¡|¿|\\|\\/){1,69}");

            var StringMessage = new FreeTextLiteral("Text",
                                                    FreeTextOptions.AllowEmpty |
                                                    FreeTextOptions.AllowEof, Environment.NewLine);

            StringMessage.Priority = 5;

            var EnclosedString = new StringLiteral("EnclosedString", "\"", StringOptions.NoEscapes);

            EnclosedString.Priority = 5;

            string IDTYPE1    = "[A-Z0-9]+?[\\.\\-_A-Z0-9]*(([A-Z]+[\\.]?[0-9]*)+?)";
            var    Identifier = new RegexBasedTerminal("Identifier", IDTYPE1);

            Identifier.Priority = 30;


            //123.25BAC_NET 1245.4A
            //12.3.FLOOR
            //FLOOR
            //FLOOR_A2
            //12.A 15.0A
            // VAR1 VAR2 OUT12 IN1 THRU IN128 AY1 TRHU AY64
            //12.5E23    <-- POSSIBLE CONFLICT BUT CORRECT NUMBER SciNotation SHOULD BE 12.5E+23
            //19.253.REG136
            //SCALTOT2
            //A12 A23.3  <-- NOT SUPPORTED BY IDTYPE1


            var LoopVariable = new RegexBasedTerminal("LoopVariable", "[A-K]");

            var LocalVariable  = new RegexBasedTerminal("LocalVariable", "[A-Z]{1}");
            var LocalVariable1 = new RegexBasedTerminal("LocalVariable1", "[A-Z0-9]");

            string PrintAscii     = "(3[2-9])|([4-9][0-9])|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])|('[A-Za-z]')";
            var    PrintableAscii = new RegexBasedTerminal("PrintableAscii", PrintAscii);

            PrintableAscii.Priority = 25;

            //RegEx Tested Strings, for ending valid Control Points
            string UPTO128 = "12[0-8]|1[0-1][0-9]|[1-9][0-9]?";
            string UPTO96  = "9[0-6]|[1-8][0-9]?";
            string UPTO64  = "6[0-4]|[1-5][0-9]?";
            string UPTO48  = "4[0-8]|[1-3][0-9]?";
            string UPTO32  = "3[0-2]|[1-2][0-9]?";
            string UPTO16  = "1[0-6]|[1-9]";
            //string UPTO8 = "[1-8]";
            string UPTO4  = "[1-4]";
            string UPTO31 = "3[0-1]|[1-2][0-9]?";
            string UPTO5  = "[1-5]";


            //Control Points
            var VARS = new RegexBasedTerminal("VARS", "VAR(" + UPTO128 + ")");

            VARS.Priority = 40;
            //adjusted for Rev6
            //TODO: Adjust EBNF too!!
            var OUTS = new RegexBasedTerminal("OUTS", "OUT(" + UPTO64 + ")");

            OUTS.Priority = 40;
            //adjusted for Rev6
            //TODO: Adjust EBNF too!!
            var INS = new RegexBasedTerminal("INS", "IN(" + UPTO64 + ")");

            INS.Priority = 40;
            //adjusted for Rev6
            //TODO: Adjust EBNF too!!
            var PRG = new RegexBasedTerminal("PRG", "PRG(" + UPTO16 + ")");

            PRG.Priority = 40;
            var DMON = new RegexBasedTerminal("DMON", "DMON(" + UPTO128 + ")");

            DMON.Priority = 40;
            var AMON = new RegexBasedTerminal("AMON", "AMON(" + UPTO96 + ")");

            AMON.Priority = 40;
            //ARRAYS ELEMENTS
            var ARR = new RegexBasedTerminal("ARR", "AY(" + UPTO48 + ")\\[\\d+\\]");

            ARR.Priority = 40;

            //Controllers, now known as PIDS
            var PIDS = new RegexBasedTerminal("PIDS", "PID(" + UPTO64 + ")");

            PIDS.Priority = 40;
            //Controllers, for backwards compatibility
            var CON = new RegexBasedTerminal("CON", "CON(" + UPTO64 + ")");

            CON.Priority = 40;
            var CONNUMBER = new RegexBasedTerminal("CONNUMBER", "(" + UPTO64 + ")");

            CON.Priority = 40;

            //Weekly Routines, now known as Schedules
            var WRS = new RegexBasedTerminal("WRS", "SCH(" + UPTO64 + ")");

            WRS.Priority = 40;
            //Anual routines, now known as Holidays
            var ARS = new RegexBasedTerminal("ARS", "HOL(" + UPTO64 + ")");

            ARS.Priority = 40;

            var GRP = new RegexBasedTerminal("GRP", "GRP(" + UPTO32 + ")");

            GRP.Priority = 40;

            var PANEL = new RegexBasedTerminal("PANEL", "(" + UPTO5 + ")");

            PANEL.Priority = 40;
            //Other sub-literals


            var DayNumber = new RegexBasedTerminal("DayNumber", "(" + UPTO31 + ")");

            DayNumber.Priority = 9;

            var TimeLiteral = new RegexBasedTerminal("TimeLiteral", "(2[0-3]|[0-1][0-9]):[0-5][0-9]:[0-5][0-9]");

            TimeLiteral.Priority = 100;
            var Ordinal = new RegexBasedTerminal("Ordinal", UPTO64);

            String Phone       = "(\\+\\d{1,2}[\\s\\.\\-])?(\\(?\\d{3}\\)?[\\s\\.\\-]?)?\\d{3,4}[\\s.-]?\\d{3,4}";
            var    PhoneNumber = new RegexBasedTerminal("PhoneNumber", Phone);

            PhoneNumber.Priority = 1;
            //v3 Manual states that only exists 5 customs tables.
            var TABLENUMBER = new RegexBasedTerminal("TABLENUMBER", "(" + UPTO5 + ")");
            //Same, up to 16 program codes (control Basic)
            var SYSPRG = new RegexBasedTerminal("SYSPRG", "(" + UPTO16 + ")");
            var TIMER  = new RegexBasedTerminal("TIMER", "(" + UPTO4 + ")");

            //KEYWORDS


            //Puctuation
            var PARIZQ           = ToTerm("(");
            var PARDER           = ToTerm(")");
            var CommandSeparator = ToTerm(";");
            var Comma            = ToTerm(",", "COMMA");

            var DDOT = ToTerm(":");

            //Operators
            //Comparisson Operators
            var AssignOp = ToTerm("=", "ASSIGN");
            var LT       = ToTerm("<", "LT");
            var GT       = ToTerm(">", "GT");
            var LTE      = ToTerm("<=", "LE");
            var GTE      = ToTerm(">=", "GE");
            var NEQ      = ToTerm("<>", "NE");
            var EQ       = ToTerm("=", "EQ");

            var NOT = ToTerm("NOT");

            //Logical Operators
            var AND = ToTerm("AND");
            var XOR = ToTerm("XOR");
            var OR  = ToTerm("OR");

            //Arithmetic Operators
            var SUM  = ToTerm("+", "PLUS");
            var SUB  = ToTerm("-", "MINUS");
            var MUL  = ToTerm("*", "MUL");
            var DIV  = ToTerm("/", "DIV");
            var IDIV = ToTerm("\\", "IDIV"); // One \ operator for integer division
            var EXP  = ToTerm("^", "POW");
            var MOD  = ToTerm("MOD");

            //Months
            var JAN = ToTerm("JAN");
            var FEB = ToTerm("FEB");
            var MAR = ToTerm("MAR");
            var APR = ToTerm("APR");
            var MAY = ToTerm("MAY");
            var JUN = ToTerm("JUN");
            var JUL = ToTerm("JUL");
            var AUG = ToTerm("AUG");
            var SEP = ToTerm("SEP");
            var OCT = ToTerm("OCT");
            var NOV = ToTerm("NOV");
            var DEC = ToTerm("DEC");

            //Days

            var SUN = ToTerm("SUN");
            var MON = ToTerm("MON");
            var TUE = ToTerm("TUE");
            var WED = ToTerm("WED");
            var THU = ToTerm("THU");
            var FRI = ToTerm("FRI");
            var SAT = ToTerm("SAT");

            //Functions

            var DOY       = ToTerm("DOY");
            var DOM       = ToTerm("DOM");
            var DOW       = ToTerm("DOW");
            var POWERLOSS = ToTerm("POWER-LOSS", "POWER_LOSS");
            var DATE      = ToTerm("DATE");
            var TIME      = ToTerm("TIME");
            var UNACK     = ToTerm("UNACK");
            var USERA     = ToTerm("USER-A", "USER_A");
            var USERB     = ToTerm("USER-B", "USER-B");
            var BEEP      = ToTerm("BEEP");
            var SCANS     = ToTerm("SCANS");



            // 2. Non-terminals

            var CONTROL_BASIC     = new NonTerminal("CONTROL_BASIC", typeof(StatementListNode));
            var SentencesSequence = new NonTerminal("SentencesSequence");
            var Sentence          = new NonTerminal("Sentence");
            var DECLAREStatement  = new NonTerminal("DECLAREStatement");
            var ENDStatement      = new NonTerminal("ENDStatement");
            var ProgramLine       = new NonTerminal("ProgramLine");
            var BasicLine         = new NonTerminal("BasicLine");

            var Subroutine          = new NonTerminal("Subroutine");
            var SubroutineSentences = new NonTerminal("SubRoutineSentences");

            //var LineNumber = new NonTerminal("LineNumber");
            var EmptyLine = new NonTerminal("EmptyLine");

            var Statement   = new NonTerminal("Statement");
            var EndProgLine = new NonTerminal("CommentOpt");

            var Commands    = new NonTerminal("Commands");
            var Command     = new NonTerminal("Command");
            var NextCommand = new NonTerminal("NextCommand");

            //Commands
            var START = new NonTerminal("START");
            var STOP  = new NonTerminal("STOP");

            var OPEN  = new NonTerminal("OPEN");
            var CLOSE = new NonTerminal("CLOSE");

            var LET               = new NonTerminal("LET");
            var ALARM             = new NonTerminal("ALARM");
            var ALARMAT           = new NonTerminal("ALARMAT");
            var CALL              = new NonTerminal("CALL");
            var CALLARGS          = new NonTerminal("CALLARGS");
            var CALLARGSLIST      = new NonTerminal("CALLARGLIST");
            var ARG               = new NonTerminal("ARG");
            var CLEAR             = new NonTerminal("CLEAR");
            var DALARM            = new NonTerminal("DALARM");
            var DISABLE           = new NonTerminal("DISABLE");
            var ENABLE            = new NonTerminal("ENABLE");
            var HANGUP            = new NonTerminal("HANGUP");
            var PHONE             = new NonTerminal("PHONE");
            var PRINT             = new NonTerminal("PRINT");
            var PRINTAT           = new NonTerminal("PRINTAT");
            var PANELS            = new NonTerminal("PANELS");
            var PrintableKeywords = new NonTerminal("PrintableKeywords");
            var REMOTEGET         = new NonTerminal("REMOTEGET");
            var REMOTESET         = new NonTerminal("REMOTESET");
            var RETURN            = new NonTerminal("RETURN");
            var RUNMACRO          = new NonTerminal("RUNMACRO");
            var SETPRINTER        = new NonTerminal("SETPRINTER");
            var PrintEverything   = new NonTerminal("FULLPRINTING");
            var PrintOnlyCommands = new NonTerminal("ONLYCOMMANDSPRINTING");
            var WAIT              = new NonTerminal("WAIT");


            var Function = new NonTerminal("Function");
            var ABS      = new NonTerminal("ABS");
            var AVG      = new NonTerminal("AVG");
            var CONPROP  = new NonTerminal("CONPROP");
            var CONRATE  = new NonTerminal("CONRATE");
            var CONRESET = new NonTerminal("CONRESET");
            var INT      = new NonTerminal("INT");
            var INTERVAL = new NonTerminal("INVERVAL");
            var LN       = new NonTerminal("LN");
            var LN1      = new NonTerminal("LN1");
            var MAX      = new NonTerminal("MAX");
            var MIN      = new NonTerminal("MIN");
            //SQR | STATUS | TBL

            var SQR    = new NonTerminal("SQR");
            var STATUS = new NonTerminal("STATUS");
            var TBL    = new NonTerminal("TBL");
            //TIMEOFF | TIMEON | WRON | WROFF

            var TIMEOFF       = new NonTerminal("TIMEOFF");
            var TIMEON        = new NonTerminal("TIMEON");
            var WRON          = new NonTerminal("WRON");
            var WROFF         = new NonTerminal("WROFF");
            var COM1          = new NonTerminal("COM1");
            var BAUDRATE      = new NonTerminal("BAUDRATE");
            var PORT          = new NonTerminal("PORT");
            var CHARS         = new NonTerminal("CHARS");
            var ComParameters = new NonTerminal("ComParameters");

            //Create Assignment statement
            var Assignment = new NonTerminal("Assignment");


            var Branch = new NonTerminal("Branch");
            //BRANCH
            //Branch ::= IF | IFTRUE | IFFALSE | GOSUB | GOTO | ON
            var IF         = new NonTerminal("IF");
            var IFTRUE     = new NonTerminal("IFTRUE");
            var IFFALSE    = new NonTerminal("IFFALSE");
            var GOSUB      = new NonTerminal("GOSUB");
            var GOTO       = new NonTerminal("GOTO");
            var ON         = new NonTerminal("ON");
            var IFCLAUSE   = new NonTerminal("IFCLAUSE");
            var ELSEOPT    = new NonTerminal("ELSEOPT");
            var GOSELECTOR = new NonTerminal("GOSELECTOR");
            var ONALARM    = new NonTerminal("ONALARM");
            var ONERROR    = new NonTerminal("ONERROR");

            //var Loop = new NonTerminal("Loop");
            var FOR     = new NonTerminal("FOR");
            var ENDFOR  = new NonTerminal("ENDFOR");
            var STEPFOR = new NonTerminal("STEPFOR");

            //Operators
            var LogicOps      = new NonTerminal("LogicOps");
            var ArithmeticOps = new NonTerminal("ArithmeticOps");
            var ComparisonOps = new NonTerminal("ComparisonOps");

            var UnaryOps  = new NonTerminal("UnaryOps");
            var BinaryOps = new NonTerminal("BinaryOps");

            var Designator       = new NonTerminal("Designator");
            var RemoteDesignator = new NonTerminal("RemoteDesignator");
            var PointIdentifier  = new NonTerminal("PointIdentifier");

            var Literal      = new NonTerminal("Literal");
            var DatesLiteral = new NonTerminal("DatesLiteral");
            var MonthLiteral = new NonTerminal("MonthLiteral");
            var DayLiteral   = new NonTerminal("DayLiteral");
            //var TimeLiteral = new NonTerminal("TimeLiteral");

            //Terms to Expressions

            var UnaryExpression      = new NonTerminal("UnaryExpression");
            var BinaryExpression     = new NonTerminal("BinaryExpression");
            var EnclosableExpression = new NonTerminal("EnclosableExpression");
            var Expression           = new NonTerminal("Expression");



            // LISTAS
            var IdentifierList    = new NonTerminal("IdentifierList");
            var LoopVariableList  = new NonTerminal("LoopVariableList");
            var ExpressionListOpt = new NonTerminal("ExpressionListOpt");
            var LineNumberListOpt = new NonTerminal("LineNumberListOpt");
            var PrintableListOpt  = new NonTerminal("PrintableListOpt");

            // 3. BNF rules

            /////////////////////
            //Set grammar root
            /////////////////////
            Root = CONTROL_BASIC;

            //CONTROL_BASIC ::= SentencesSequence | SubRoutine
            CONTROL_BASIC.Rule = SentencesSequence | Subroutine;

            #region Encoded Subroutines
            //SubRoutine ::= (LineNumber DECLARE EndLine SentencesSequence LineNumber END)
            Subroutine.Rule = DECLAREStatement + SubroutineSentences;

            //DECLARE::= 'DECLARE' Identifier(',' Identifier) *
            DECLAREStatement.Rule    = LineNumber + ToTerm("DECLARE") + IdentifierList + NewLine;
            SubroutineSentences.Rule = SentencesSequence;

            ENDStatement.Rule = LineNumber + ToTerm("END", "ENDPRG");
            #endregion


            IdentifierList.Rule = MakePlusRule(IdentifierList, Identifier);
            //SentencesSequence ::= ProgramLine+
            SentencesSequence.Rule = MakeStarRule(SentencesSequence, ProgramLine);
            //ProgramLine ::= EmptyLine | (LineNumber Sentence EndLine)
            //ProgramLine.Rule = EmptyLine | (LineNumber + Sentence + ReduceHere() + EndProgLine);
            ProgramLine.Rule = LineNumber + Sentence + EndProgLine;

            //EndProgLine.Rule = Comment.Q() + NewLine;
            EndProgLine.Rule = PreferShiftHere() + Comment.Q() + NewLine;

            //EmptyLine ::= LineNumber? EndLine
            //EmptyLine.Rule = LineNumber.Q() + NewLine;
            EmptyLine.Rule = Empty;

            //Sentence ::= (Comment | (Commands| Assignment | Branch | Loop) Comment?)
            //Sentence.Rule = Comment | ((ToTerm("END") + ReduceHere() | Commands | Assignment | Branch | FOR | ENDFOR) + Comment.Q()  );
            Sentence.Rule = ToTerm("END") | Commands | Assignment | Branch | FOR | ENDFOR | Comment;


            //Commands::= Command (';' Command) *
            Commands.Rule = Command + NextCommand;

            //Command ::= ALARM | ALARMAT | CALL | CLEAR | DALARM | DISABLE | ENABLE |
            //END | HANGUP | ONALARM | ONERROR  | PHONE | PRINT | PRINTAT | REMOTEGET
            //| REMOTESET | RETURN | RUNMACRO | SETPRINTER | START | STOP | WAIT
            //| OPEN | CLOSE
            Command.Rule = ALARM | ALARMAT | CALL | CLEAR | DALARM | DISABLE | ENABLE | HANGUP
                           | PHONE | PRINT | PRINTAT | REMOTEGET | REMOTESET | RETURN | RUNMACRO | SETPRINTER
                           | START | STOP | WAIT | OPEN | CLOSE;

            NextCommand.Rule = MakeStarRule(NextCommand, CommandSeparator + Command);


            //TODO: ALARM, Waiting for information previously asked to TEMCO
            //ALARM ::= 'ALARM' Expression ComparisonOps Expression ',' Expression ',' StringLiteral*
            ALARM.Rule = "ALARM" + Expression + ComparisonOps + Expression + Comma + Expression + Comma + StringMessage;
            //DALARM ::= 'DALARM' Expression ',' NumberLiteral ',' StringLiteral+
            DALARM.Rule = "DALARM" + Expression + Comma + Number + Comma + StringMessage;
            //DISABLE ::= 'DISABLE' Identifier



            PRINT.Rule             = "PRINT" + PrintableKeywords + PrintableListOpt;
            PrintableKeywords.Rule = DATE | TIME | USERA | USERB | BEEP | PointIdentifier | EnclosedString;
            PrintableListOpt.Rule  = MakeStarRule(PrintableListOpt, CommandSeparator + PrintableKeywords);

            //REMOTEGET ::= 'REMOTE-GET' Designator AssignOp RemoteDesignator
            //REMOTESET::= 'REMOTE-SET' RemoteDesignator AssignOp Designator
            REMOTEGET.Rule = "REMOTE-GET" + Designator + AssignOp + RemoteDesignator;
            REMOTESET.Rule = "REMOTE-SET" + RemoteDesignator + AssignOp + Designator;



            #region ENCODED COMMANDS

            PHONE.Rule = ToTerm("PHONE", "PHONE") + PhoneNumber;

            PRINTAT.Rule = ToTerm("PRINT-AT", "PRINT_AT") + (PANELS | ToTerm("ALL", "ALL"));
            PANELS.Rule  = MakePlusRule(PANELS, PANEL);

            SETPRINTER.Rule        = PrintEverything | PrintOnlyCommands;
            PrintEverything.Rule   = ToTerm("SET-PRINTER", "SET_PRINTER") + (ToTerm("A", "PRT_A") | ToTerm("B", "PRT_B") | ToTerm("0", "PRT_0"));
            PrintOnlyCommands.Rule = "Set-Printer" + (ToTerm("a") | ToTerm("b") | ToTerm("0"));

            //ALARMAT ::= 'ALARM-AT' PANELS | 'ALL'
            ALARMAT.Rule = ToTerm("ALARM-AT", "ALARM_AT") + (PANELS | ToTerm("ALL", "ALL"));

            //RUNMACRO::= 'RUN-MACRO' SYSPRG
            RUNMACRO.Rule       = ToTerm("RUN-MACRO", "RUN_MACRO") + SYSPRG;
            RUNMACRO.Precedence = 200;

            //CALL ::= 'CALL' PRG (AssignOp ARG (Space ',' Space ARG)* )?
            //TODO: CALL, Check if it works with expressions
            CALL.Rule         = "CALL" + PRG + CALLARGS.Q();
            CALLARGS.Rule     = AssignOp + ARG + CALLARGSLIST;
            CALLARGSLIST.Rule = MakeStarRule(CALLARGSLIST, Comma + ARG);
            ARG.Rule          = Designator | Expression;

            #region Decoded
            START.Rule = "START" + Designator;
            STOP.Rule  = "STOP" + Designator;

            OPEN.Rule  = "OPEN" + Designator;
            CLOSE.Rule = "CLOSE" + Designator;

            WAIT.Rule   = "WAIT" + Expression;
            CLEAR.Rule  = ToTerm("CLEAR", "CLEAR");
            RETURN.Rule = ToTerm("RETURN", "RETURN");
            HANGUP.Rule = ToTerm("HANGUP");

            DISABLE.Rule = ToTerm("DISABLE", "DISABLEX") + Designator;
            ENABLE.Rule  = ToTerm("ENABLE", "ENABLEX") + Designator;
            #endregion

            //Assignment ::= Designator AssignOp Expression
            LET.Rule        = "LET";
            Assignment.Rule = LET.Q() + Designator + AssignOp + Expression;


            //Branch ::= IF | IFTRUE | IFFALSE | GOSUB | GOTO | ON
            //   IF::= 'IF' Expression 'THEN' IFCLAUSE('ELSE' IFCLAUSE) ?
            //  IFTRUE::= 'IF+' Expression 'THEN' IFCLAUSE('ELSE' IFCLAUSE) ?
            // IFFALSE::= 'IF-' Expression 'THEN' IFCLAUSE('ELSE' IFCLAUSE) ?
            //IFCLAUSE::= (Sentence | LineNumber)

            Branch.Rule = IF | IFTRUE | IFFALSE | GOSUB | GOTO | ON | ONALARM | ONERROR;
            IF.Rule     = "IF" + Expression + "THEN" + IFCLAUSE + ELSEOPT.Q();

            IFTRUE.Rule  = "IF+" + Expression + "THEN" + IFCLAUSE + ELSEOPT.Q();
            IFFALSE.Rule = "IF-" + Expression + "THEN" + IFCLAUSE + ELSEOPT.Q();
            //Added Function for testing purposes: Error found on a sample code PRG1 of BTUMETERrev22.prg
            IFCLAUSE.Rule = Commands | Function | Assignment | GOSELECTOR | LineNumber;

            //ELSEOPT.Rule = "ELSE" + IFCLAUSE;
            ELSEOPT.Rule = PreferShiftHere() + ToTerm("ELSE", "ELSE") + IFCLAUSE;

            #region JUMPS
            //ON ::= 'ON' IntegerTerm (GOTO | GOSUB) (',' LineNumber)*
            ON.Rule                = ToTerm("ON") + Expression + GOSELECTOR + LineNumberListOpt;
            GOSELECTOR.Rule        = GOTO | GOSUB;
            LineNumberListOpt.Rule = MakeStarRule(LineNumberListOpt, Comma + LineNumber);
            //GOSUB::= 'GOSUB' LineNumber
            GOSUB.Rule = "GOSUB" + LineNumber;
            //GOTO ::= 'GOTO' LineNumber
            GOTO.Rule = "GOTO" + LineNumber;

            ONALARM.Rule = ToTerm("ON-ALARM", "ON_ALARM") + LineNumber;
            ONERROR.Rule = ToTerm("ON-ERROR", "ON_ERROR") + LineNumber;
            #endregion

            #endregion


            //Loop::= FOR SentencesSequence ENDFOR
            //FOR::= 'FOR' LoopVariable AssignOp Integer 'TO' Integer('STEP' Integer) ? EndLine
            //ENDFOR::= 'NEXT'(LoopVariable(',' LoopVariable) *) ?
            //Loop.Rule  = FOR + SentencesSequence | ENDFOR ;
            FOR.Rule              = ToTerm("FOR") + LoopVariable + AssignOp + IntegerNumber + ToTerm("TO") + IntegerNumber + STEPFOR;
            STEPFOR.Rule          = Empty | (ToTerm("STEP") + IntegerNumber);
            ENDFOR.Rule           = ToTerm("NEXT") + LoopVariableList;
            LoopVariableList.Rule = MakePlusRule(LoopVariableList, Comma, LoopVariable);


            LogicOps.Rule      = AND | OR | XOR;
            ArithmeticOps.Rule = SUM | SUB | MUL | DIV | IDIV | MOD | EXP;
            ComparisonOps.Rule = EQ | NEQ | GT | LT | LTE | GTE;

            UnaryOps.Rule  = NOT;
            BinaryOps.Rule = ArithmeticOps | ComparisonOps | LogicOps;


            //LineNumber.Rule = IntegerNumber;
            //PointIdentifier ::= VARS | CONS | WRS | ARS | OUTS | INS | PRG | GRP | DMON | AMON | ARR
            PointIdentifier.Rule = VARS | PIDS | WRS | ARS | OUTS | INS | PRG | GRP | DMON | AMON | ARR | CON;

            //Designator ::= Identifier | PointIdentifier | LocalVariable
            Designator.Rule       = PointIdentifier | Identifier | LocalVariable;
            RemoteDesignator.Rule = Designator;

            DayLiteral.Rule   = SUN | MON | TUE | WED | THU | FRI | SAT;
            MonthLiteral.Rule = JAN | FEB | MAR | APR | MAY | JUN | JUL | AUG | SEP | OCT | NOV | DEC;

            //DatesLiteral ::= MonthLiteral Space ([1-2] [1-9] | [3] [0-1])
            DatesLiteral.Rule = MonthLiteral + DayNumber;
            //TimeLiteral ::= HH ':' MM ':' SS
            //TimeLiteral.Rule = HH + DDOT + MM + DDOT + SS;
            //Literal ::= NumbersLiteral | DatesLiteral | DaysLiteral | TimeLiteral
            Literal.Rule = IntegerNumber | Number | DatesLiteral | DayLiteral | TimeLiteral;

            #region 27 FUNCTIONS
            //27 Functions
            //Function::= ABS | AVG | CONPROP | CONRATE | CONRESET | DOM | DOW | DOY |
            //INT | INTERVAL | LN | LN1 | MAX | MIN | POWERLOSS | SCANS | SQR | STATUS | TBL |
            //TIME | TIMEOFF | TIMEON | WRON | WROFF | UNACK | USERA | USERB
            Function.Rule = ABS | AVG | CONPROP | CONRATE | CONRESET | COM1 | DOY | DOM |
                            DOW | INT | INTERVAL | LN | LN1 | MAX | MIN | POWERLOSS | SCANS | SQR | STATUS
                            | TBL | TIME | TIMEON | TIMEOFF | WRON | WROFF | UNACK | USERA | USERB;

            ABS.Rule = "ABS" + PARIZQ + Expression + PARDER;
            //INT      ::= 'INT' PARIZQ Expression PARDER
            INT.Rule = ToTerm("INT", "_INT") + PARIZQ + Expression + PARDER;
            //INTERVAL::= 'INTERVAL' PARIZQ Expression PARDER
            INTERVAL.Rule = "INTERVAL" + PARIZQ + Expression + PARDER;
            //LN::= 'LN' PARIZQ Expression PARDER
            LN.Rule = "LN" + PARIZQ + Expression + PARDER;
            //LN1 ::= 'LN-1' PARIZQ Expression PARDER
            LN1.Rule = ToTerm("LN-1", "LN_1") + PARIZQ + Expression + PARDER;
            //SQR ::= 'SQR' PARIZQ Expression PARDER
            SQR.Rule = "SQR" + PARIZQ + Expression + PARDER;
            //STATUS ::= 'STATUS' PARIZQ Expression PARDER
            STATUS.Rule = ToTerm("STATUS", "_Status") + PARIZQ + Expression + PARDER;

            #region Functions with variable list of expressions, must add count of expressions as last token.
            //AVG      ::= 'AVG' PARIZQ EXPRESSION ( Space ',' Space EXPRESSION )* PARDER
            AVG.Rule = "AVG" + PARIZQ + Expression + ExpressionListOpt + PARDER;
            //MAX ::= 'MAX' PARIZQ Expression (Space ',' Space Expression)*PARDER
            MAX.Rule = "MAX" + PARIZQ + Expression + ExpressionListOpt + PARDER;
            //MIN::= 'MIN' PARIZQ Expression (Space ',' Space Expression)*PARDER
            MIN.Rule = "MIN" + PARIZQ + Expression + ExpressionListOpt + PARDER;
            #endregion

            #region Functions not tested yet with enconding, PENDING FROM TEMCO
            //CONPROP  ::= 'CONPROP' PARIZQ Ordinal ',' Expression PARDER
            CONPROP.Rule = "CONPROP" + PARIZQ + CONNUMBER + Comma + Expression + PARDER;

            //CONRATE  ::= 'CONRATE' PARIZQ Ordinal ',' Expression PARDER RANGE
            CONRATE.Rule = "CONRATE" + PARIZQ + CONNUMBER + Comma + Expression + PARDER;

            //CONRESET ::= 'CONRESET' PARIZQ Ordinal ',' Expression PARDER RANGE
            CONRESET.Rule = "CONRESET" + PARIZQ + CONNUMBER + Comma + Expression + PARDER;

            //TBL ::= 'TBL' PARIZQ Expression ',' TABLENUMBER PARDER
            TBL.Rule = "TBL" + PARIZQ + Expression + Comma + TABLENUMBER + PARDER;
            //TIMEON ::= 'TIME-ON' PARIZQ Designator PARDER

            TIMEON.Rule = ToTerm("TIME-ON", "TIME_ON") + PARIZQ + Designator + PARDER;

            //TIMEOFF::= 'TIME-OFF' PARIZQ Designator PARDER
            TIMEOFF.Rule = ToTerm("TIME-OFF", "TIME_OFF") + PARIZQ + Designator + PARDER;
            //WRON ::= 'WR-ON' PARIZQ SYSPRG ',' TIMER PARDER
            WRON.Rule = ToTerm("WR-ON", "WR_ON") + PARIZQ + SYSPRG + Comma + TIMER + PARDER;
            //WROFF::= 'WR-OFF' PARIZQ SYSPRG ',' TIMER PARDER
            WROFF.Rule = ToTerm("WR-OFF", "WR_OFF") + PARIZQ + SYSPRG + Comma + TIMER + PARDER;


            //COM1 ::= 'COM1' PARIZQ BAUDRATE ',' PORT (CHARS+ | ',' EnclosedString) PARDER
            //BAUDRATE::= '9600' | '115200'
            //PORT::= '1' | 'Z' | 'Y' | 'X'
            //CHARS::= ','(PrintableAscii | ['] [A-Za-z] ['])
            //PrintableAscii::= '3'[2 - 9] | [4 - 9][0 - 9] | '1'[0 - 9][0 - 9] | '2'[0 - 4][0 - 9] | '25'[0 - 5]

            COM1.Rule          = "COM1" + PARIZQ + BAUDRATE + Comma + PORT + ComParameters + PARDER;
            BAUDRATE.Rule      = ToTerm("9600") | ToTerm("115200");
            PORT.Rule          = ToTerm("1") | ToTerm("Z") | ToTerm("Y") | ToTerm("X");
            ComParameters.Rule = CHARS | EnclosedString;
            CHARS.Rule         = MakePlusRule(CHARS, Comma + PrintableAscii);
            #endregion

            #endregion

            //EXPR.Rule = number | variable | FUN_CALL | stringLiteral | BINARY_EXPR
            //          | "(" + EXPR + ")" | UNARY_EXPR;
            Expression.Rule =
                Function
                | Literal
                | Designator
                | UnaryExpression
                | BinaryExpression
                | EnclosableExpression;

            //UnaryExpression ::=  UnaryOps Term
            UnaryExpression.Rule = UnaryOps + Expression;
            //BinaryExpression::= Expression BinaryOps Expression
            BinaryExpression.Rule = Expression + BinaryOps + Expression;

            //EnclosableExpression ::= ParIzq SimpleExpression ParDer
            EnclosableExpression.Rule = PARIZQ + Expression + PARDER;

            ExpressionListOpt.Rule = MakeStarRule(ExpressionListOpt, Comma + Expression);


            RegisterBracePair(PARIZQ.ToString(), PARDER.ToString());
            RegisterBracePair("(", ")");
            RegisterBracePair("[", "]");
            RegisterBracePair("DECLARE", "END");

            // 4. Operators precedence
            RegisterOperators(100, Associativity.Right, EXP);
            RegisterOperators(90, MUL, DIV, IDIV);
            RegisterOperators(80, MOD);
            RegisterOperators(70, SUM, SUB);

            RegisterOperators(60, LT, GT, LTE, GTE, EQ, NEQ);

            RegisterOperators(50, Associativity.Right, NOT);
            RegisterOperators(50, AND, OR, XOR);


            //// 5. Punctuation and transient terms
            MarkPunctuation(PARIZQ.ToString(), PARDER.ToString(), CommandSeparator.ToString());
            PARIZQ.IsPairFor = PARDER;


            //MarkTransient(LineNumber);



            //MarkTransient(CodeLine, ProgramLine,
            //    Term, Expression,
            //    BinaryOperator, UnaryOperator,
            //    AssignmentOperator,//FunctionOperator,
            //    ParentExpression);

            LanguageFlags =
                //LanguageFlags.CreateAst |
                LanguageFlags.NewLineBeforeEOF;

            #region Define Keywords

            //GENERAL KEYWORDS
            MarkReservedWords("DECLARE", "END", "FOR", "NEXT", "TO", "STEP", "NOT");
            //27 FUNCTIONS
            //9 Non parenthesis enclosed functions
            MarkReservedWords("DOY", "DOM", "DOW", "POWER-LOSS", "DATE", "TIME", "UNACK", "USER-A", "USER-B", "SCANS");
            //18 Parenthesis enclosed functions
            MarkReservedWords("ABS", "AVG", "CONPROP", "CONRATE", "CONRESET", "INT", "INTERVAL");
            MarkReservedWords("LN", "LN-1", "MAX", "MIN", "SQR", "STATUS", "TBL", "TIME-ON", "TIME-OFF");
            MarkReservedWords("WR-ON", "WR-OFF", "COM1");
            //Branches
            MarkReservedWords("IF", "IF+", "IF-", "ON-ALARM", "ON-ERROR", "ON", "GOTO", "GOSUB", "ELSE", "THEN");
            //Commands
            MarkReservedWords("START", "STOP", "OPEN", "CLOSE", "LET", "ALARM", "ALARM-AT", "CALL", "ALL");
            MarkReservedWords("CLEAR", "DALARM", "DISABLE", "ENABLE", "HANGUP", "PHONE", "PRINT",
                              "PRINT-AT", "REMOTE-GET", "REMOTE-SET", "RETURN", "RUN-MACRO", "WAIT",
                              "SET-PRINTER", "Set-Printer");


            MarkReservedWords("AND", "OR", "XOR");
            #endregion
        }
Esempio n. 4
0
        // BASIC is not case sensitive...
        public GWBasicGrammar()
            : base(false)
        {
            this.GrammarComments = "This grammar uses one new Irony feature - Scanner-Parser link. Parser helps Scanner to disambiguate " +
                             "similar but different token types when more than one terminal matches the current input char.\r\n" +
                             "See comments in GwBasicGrammar.cs file.";
              /*
               Scanner-Parser link.
               The grammar defines 3 terminals for numbers: number, lineNumber and fileNumber. All three return decimal
               digits in GetFirsts() method. So when current input is a digit, the scanner has 3 potential candidate terminals
               to match the input. However, because each of the 3 terminals can appear in specific "places" in grammar,
               the parser is able to assist scanner to pick the correct terminal, depending on the current parser state.
               The disambiguation happens in Scanner.SelectTerminals method. When the terminal list for current input char
               has more than 1 terminal, the scanner code gets the current parser state from core parser (through compilerContext),
               and then checks the terminals agains the ExpectedTerms set in the parser state.
               As you might see in Grammar Explorer, the conflict is resolved successfully.
               */

            //Terminals
            var lineNumber = new NumberLiteral("LINE_NUMBER", NumberOptions.IntOnly);
            var fileNumber = new NumberLiteral("FILE_NUMBER", NumberOptions.IntOnly);

            var number = new NumberLiteral("NUMBER", NumberOptions.AllowStartEndDot);
            //ints that are too long for int32 are converted to int64
            number.DefaultIntTypes = new TypeCode[] {TypeCode.Int32, TypeCode.Int64};
            number.AddExponentSymbols("eE", TypeCode.Single);
            number.AddExponentSymbols("dD", TypeCode.Double);
            number.AddSuffix("!", TypeCode.Single);
            number.AddSuffix("#", TypeCode.Double);

            var variable = new IdentifierTerminal("Identifier");
            variable.AddSuffix("$", TypeCode.String);
            variable.AddSuffix("%", TypeCode.Int32);
            variable.AddSuffix("!", TypeCode.Single);
            variable.AddSuffix("#", TypeCode.Double);

            var stringLiteral = new StringLiteral("STRING", "\"", StringOptions.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 line_cont = new LineContinuationTerminal("LineContinuation", "_");
            var comma = ToTerm(",", "comma");
            var colon = ToTerm(":", "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 | "#";

            // Non-terminals
            var PROGRAM = new NonTerminal("PROGRAM");
            var LINE = new NonTerminal("LINE");
            var LINE_CONTENT_OPT = new NonTerminal("LINE_CONTENT_OPT");
            var COMMENT_OPT = new NonTerminal("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", "operator");
            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 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");
            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;

            // BNF Rules
            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_OPT + COMMENT_OPT + NewLine | SyntaxError + NewLine;
            LINE.NodeCaptionTemplate = "Line #{0}";

            // A statement list is 1 or more statements separated by the ':' character
            LINE_CONTENT_OPT.Rule = Empty | IF_STMT | STATEMENT_LIST;
            STATEMENT_LIST.Rule = MakePlusRule(STATEMENT_LIST, colon, STATEMENT);
            COMMENT_OPT.Rule = short_comment | 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 = ToTerm("o") | "i" | "a" | "output" | "input" | "append";
            CLOSE_STMT.Rule = "close" + pound_opt + fileNumber;
            LINE_INPUT_STMT.Rule = ToTerm("line") + "input" + semi_opt + stringLiteral + ";" + VARIABLE_OR_FUNCTION_EXPR;
            LINE_INPUT_POUND_STMT.Rule = ToTerm("line") + "input" + ToTerm("#") + 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_STMT;

            //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 + (ToTerm("goto") | "gosub") + LINE_NUMBERS;
            LINE_NUMBERS.Rule = MakePlusRule(LINE_NUMBERS, comma, lineNumber);
            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 = ToTerm("clear") + comma + (Empty | number) + (Empty | comma + number) | "clear" + number | "clear";
            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 = ToTerm("-") | "+";

            //Inject PreferShift hint here to explicitly set shift as preferred action. Suppresses warning message about conflict.
            //The conflict arises from PRINT statement, when there may be ambigous interpretations for expression like
            //  PRINT F (X) -- either function call or identifier followed by expression
            FUN_CALL.Rule = variable + PreferShiftHere() + "(" + ARG_LIST + ")";
            VARIABLE_OR_FUNCTION_EXPR.Rule = variable | FUN_CALL;

            BINARY_OP.Rule = ToTerm("+") | "^" | "-" | "*" | "/" | "=" | "<=" | ">=" | "<" | ">" | "<>" | "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, 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);

            //Punctuation and Transient elements
            MarkPunctuation("(", ")", ",");
            MarkTransient(EXPR, STATEMENT, LINE_CONTENT_OPT, VARIABLE_OR_FUNCTION_EXPR, COMMENT_OPT);
            NonGrammarTerminals.Add(line_cont);

            this.LanguageFlags = LanguageFlags.NewLineBeforeEOF;

            lineNumber.ValidateToken += lineNumber_ValidateToken;
        }
Esempio n. 5
0
        public Language()
        {
            var singleLineComment = new CommentTerminal("Comment", "--", "\r", "\n", "\u2085", "\u2028", "\u2029");
            var multilineComment  = new LuaLongCommentTerminal("Comment");

            var normalString = new LuaStringLiteral("String");

            var number = new NumberLiteral("Number", NumberOptions.AllowStartEndDot);

            number.AddPrefix("0x", NumberOptions.Hex);
            number.AddExponentSymbols("eE", TypeCode.Double);
            number.DefaultIntTypes  = new TypeCode[] { TypeCode.Double };
            number.DefaultFloatType = TypeCode.Double;

            var name = new IdentifierTerminal("Name");

            var nil    = new KeyTerm("nil", "Nil");
            var @true  = new KeyTerm("true", "True");
            var @false = new KeyTerm("false", "False");

            var namelist = new NonTerminal("NameList");

            var chunk   = new NonTerminal("Chunk");
            var block   = new NonTerminal("Block");
            var stat    = new NonTerminal("Statement");
            var retstat = new NonTerminal("Return");

            var label = new NonTerminal("Label");

            var funcname        = new NonTerminal("FunctionName");
            var funcname_normal = new NonTerminal("FunctionName_Normal");
            var funcname_self   = new NonTerminal("FunctionName_Self");

            var variables = new NonTerminal("Variables");
            var variable  = new NonTerminal("Variable");
            var property  = new NonTerminal("Property");
            var index     = new NonTerminal("Index");

            var explist    = new NonTerminal("ExpressionList");
            var expression = new NonTerminal("Expression");

            var binop       = new NonTerminal("BinaryOperation");
            var binoperator = new NonTerminal("BinaryOperator");
            var unop        = new NonTerminal("UnaryOperation");
            var unoperator  = new NonTerminal("UnaryOperator");

            var functiondef      = new NonTerminal("FunctionDefinition");
            var tableconstructor = new NonTerminal("TableConstructor");
            var functioncall     = new NonTerminal("FunctionCall");
            var args             = new NonTerminal("Arguments");
            var funcbody         = new NonTerminal("FunctionBody");
            var parlist          = new NonTerminal("ParameterList");

            var field     = new NonTerminal("Field");
            var fieldsep  = new NonTerminal("FieldSeperator");
            var fieldlist = new NonTerminal("FieldList");


            var global_assignment = new NonTerminal("GlobalAssignment");
            var local_assignment  = new NonTerminal("LocalAssignment");
            var @break            = new NonTerminal("Break");
            var @goto             = new NonTerminal("Goto");
            var scope             = new NonTerminal("Scope");
            var forLoopEnumerable = new NonTerminal("ForLoop_Enumerable");
            var forLoopIterable   = new NonTerminal("ForLoop_Iterable");
            var whileLoop         = new NonTerminal("WhileLoop");
            var repeatLoop        = new NonTerminal("RepeatLoop");
            var ifStatement       = new NonTerminal("IfStatement");
            var elseifStatement   = new NonTerminal("ElseIfStatement");
            var elseifStatements  = new NonTerminal("ElseIfStatements");
            var elseStatement     = new NonTerminal("ElseStatement");
            var globalFunction    = new NonTerminal("GlobalFunction");
            var localFunction     = new NonTerminal("LocalFunction");
            var @return           = new NonTerminal("ReturnStatement");

            var assignmentValues      = new NonTerminal("AssignmentValues");
            var localAssignmentValues = new NonTerminal("LocalAssignmentValues");

            var functioncall_normal   = new NonTerminal("FunctionCall_Normal");
            var functioncall_instance = new NonTerminal("FunctionCall_Instance");

            MarkTransient(expression, stat, localAssignmentValues, binoperator, unoperator, assignmentValues, chunk);

            MarkMemberSelect(".", ":", "[");
            MarkReservedWords("if", "for", "while", "repeat", "do", "end", "break", "return", "local", "function", "false", "true", "nil");
            MarkPunctuation("=", "'", "\"", ".", ":", "::", "[", "]", "(", ")", "return", "if", "for", "then", "else", "elseif", "while", "repeat", "do", "end", "local", "function", "goto");
            RegisterBracePair("[", "]");
            RegisterBracePair("[[", "]]");
            RegisterBracePair("[=[", "]=]");
            RegisterBracePair("[==[", "]==]");
            RegisterBracePair("[===[", "]===]");
            RegisterBracePair("{", "}");
            RegisterBracePair("(", ")");


            chunk.Rule = block;
            block.Rule = MakeStarRule(block, stat);

            stat.Rule = ToTerm(";")
                        | global_assignment
                        | local_assignment
                        | functioncall
                        | label
                        | @break
                        | @goto
                        | scope
                        | forLoopEnumerable
                        | forLoopIterable
                        | whileLoop
                        | repeatLoop
                        | ifStatement
                        | globalFunction
                        | localFunction
                        | retstat
                        | singleLineComment
                        | multilineComment
            ;

            assignmentValues.Rule      = ToTerm("=") + explist;
            localAssignmentValues.Rule = ToTerm("=") + explist | Empty;


            global_assignment.Rule = variables + assignmentValues;
            local_assignment.Rule  = ToTerm("local") + variables + localAssignmentValues;
            @break.Rule            = ToTerm("break");
            @goto.Rule             = ToTerm("goto") + name;
            scope.Rule             = ToTerm("do") + block + "end";
            forLoopIterable.Rule   = ToTerm("for") + name + "=" + expression + "," + expression + ("," + expression).Q() + "do" + block + "end";
            forLoopEnumerable.Rule = ToTerm("for") + variables + "in" + explist + "do" + block + "end";
            whileLoop.Rule         = ToTerm("while") + expression + "do" + block + "end";
            repeatLoop.Rule        = ToTerm("repeat") + block + "until" + expression;
            ifStatement.Rule       = ToTerm("if") + expression + "then" + block + elseifStatements + elseStatement + "end";
            elseifStatement.Rule   = ToTerm("elseif") + expression + "then" + block;
            elseifStatements.Rule  = MakeStarRule(elseifStatements, elseifStatement);
            elseStatement.Rule     = "else" + block | Empty;
            globalFunction.Rule    = ToTerm("function") + funcname + funcbody;
            localFunction.Rule     = ToTerm("local") + "function" + name + funcbody;

            retstat.Rule  = ToTerm("return") + explist;
            label.Rule    = ToTerm("::") + name + "::";
            namelist.Rule = MakePlusRule(namelist, ToTerm(","), name);

            funcname.Rule        = funcname_normal | funcname_self;
            funcname_normal.Rule = MakePlusRule(funcname_normal, ToTerm("."), name);
            funcname_self.Rule   = funcname + ":" + name;

            explist.Rule = MakeListRule(explist, ToTerm(","), expression, TermListOptions.StarList);

            expression.Rule = PreferShiftHere() + nil
                              | @true
                              | @false
                              | number
                              | variable
                              | functioncall
                              | normalString
                              | "..."
                              | functiondef
                              | tableconstructor
                              | binop
                              | unop;
            expression.ErrorAlias = "valid expression";

            functioncall.Rule = functioncall_normal | functioncall_instance;


            //LALR supporting prefixes
            variables.Rule = MakeListRule(variables, ToTerm(","), variable, TermListOptions.PlusList);
            property.Rule  = variable + "." + name | functioncall + "." + name;
            index.Rule     = variable + "[" + expression + "]" | functioncall + "[" + expression + "]";
            variable.Rule  = name | property | index | "(" + expression + ")";


            functioncall_instance.Rule = variable + ":" + name + args | functioncall + ":" + name + args;
            functioncall_normal.Rule   = variable + args | functioncall + args;

            args.Rule = ToTerm("(") + explist + ")" | tableconstructor | normalString;

            functiondef.Rule = ToTerm("function") + funcbody;
            funcbody.Rule    = ToTerm("(") + parlist + ")" + block + "end";

            parlist.Rule          = namelist | namelist + "," + "..." | "..." | Empty;
            tableconstructor.Rule = ToTerm("{") + fieldlist + "}";

            fieldsep.Rule = ToTerm(",") | ";";
            //WARNING: Doesn't allow trailing delimiter ( { field1, field2, } )
            fieldlist.Rule = MakeListRule(fieldlist, fieldsep, field, TermListOptions.StarList | TermListOptions.AddPreferShiftHint);
            field.Rule     = (ToTerm("[") + expression + "]" + "=" + expression) | (name + "=" + expression) | expression;


            var binMinus = ToTerm("-");
            var unMinus  = ToTerm("-");

            binoperator.Rule = ToTerm("+") | binMinus | "*" | "/" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | "and" | "or";
            unoperator.Rule  = unMinus | "#" | "not";
            unoperator.SetFlag(TermFlags.IsOperator);
            binoperator.SetFlag(TermFlags.IsOperator);


            RegisterOperators(5, Associativity.Left, "^", "%", "..");
            RegisterOperators(4, Associativity.Left, "/");
            RegisterOperators(2, Associativity.Left, "*");
            RegisterOperators(2, Associativity.Right, unMinus);
            RegisterOperators(1, Associativity.Left, "+");
            RegisterOperators(0, Associativity.Left, binMinus);
            RegisterOperators(-1, Associativity.Left, "<", "<=", ">", ">=", "==", "~=", "and", "or");

            binop.Rule = expression + binoperator + expression;
            unop.Rule  = ReduceHere() + unoperator + expression;

            this.Root = chunk;
        }