Esempio n. 1
0
        private static void ParseOperand(ASTNode node, string lexeme)
        {
            bool modifier = false;

            // An operand may start with an '@' symbol. Pick that
            // off.
            if (lexeme[0] == '@')
            {
                node.Push(ASTNodeType.QUIET, null, _curLine);
                lexeme   = lexeme.Substring(1, lexeme.Length - 1);
                modifier = true;
            }

            // An operand may end with a '!' symbol. Pick that
            // off.
            if (lexeme.EndsWith("!"))
            {
                node.Push(ASTNodeType.FORCE, null, _curLine);
                lexeme   = lexeme.Substring(0, lexeme.Length - 1);
                modifier = true;
            }

            if (!modifier)
            {
                ParseValue(node, lexeme, ASTNodeType.OPERAND);
            }
            else
            {
                node.Push(ASTNodeType.OPERAND, lexeme, _curLine);
            }
        }
Esempio n. 2
0
        private static void ParseForLoop(ASTNode statement, string[] lexemes)
        {
            // There are 4 variants of for loops in steam. The simplest two just
            // iterate a fixed number of times. The other two iterate
            // parts of lists. We call those second two FOREACH.

            // We're intentionally deprecating two of the variants here.
            // The for X to Y variant, where both X and Y are integers,
            // is useless. It can be just written as for X.
            // The for X to Y in LIST variant may have some niche uses, but
            // is annoying to implement.

            // The for X loop remains supported as is, while the
            // for X in LIST form is actually transformed into a foreach
            // statement.

            if (lexemes.Length == 1)
            {
                // for X
                var loop = statement.Push(ASTNodeType.FOR, null, _curLine);

                ParseValue(loop, lexemes[0], ASTNodeType.STRING);
            }
            else
            {
                throw new SyntaxError(statement, "Invalid for loop");
            }
        }
Esempio n. 3
0
        private static void ParseBinaryExpression(ASTNode node, string[] lexemes)
        {
            var expr = node.Push(ASTNodeType.BINARY_EXPRESSION, null, _curLine);

            int i = 0;

            // The expressions on either side of the operator can be values
            // or operands that need to be evaluated.
            ParseOperand(expr, lexemes[i++]);

            for (; i < lexemes.Length; i++)
            {
                if (IsOperator(lexemes[i]))
                {
                    break;
                }

                ParseValue(expr, lexemes[i], ASTNodeType.STRING);
            }

            ParseOperator(expr, lexemes[i++]);

            ParseOperand(expr, lexemes[i++]);

            for (; i < lexemes.Length; i++)
            {
                if (IsOperator(lexemes[i]))
                {
                    break;
                }

                ParseValue(expr, lexemes[i], ASTNodeType.STRING);
            }
        }
Esempio n. 4
0
        private static void ParseLogicalExpression(ASTNode node, string[] lexemes)
        {
            // The steam language supports logical operators 'and' and 'or'.
            // Catch those and split the expression into pieces first.
            // Fortunately, it does not support parenthesis.
            var  expr    = node;
            bool logical = false;
            int  start   = 0;

            for (int i = start; i < lexemes.Length; i++)
            {
                if (lexemes[i] == "and" || lexemes[i] == "or")
                {
                    if (!logical)
                    {
                        expr    = node.Push(ASTNodeType.LOGICAL_EXPRESSION, null, _curLine);
                        logical = true;
                    }

                    ParseExpression(expr, lexemes.Slice(start, i - 1));
                    start = i + 1;
                    expr.Push(lexemes[i] == "and" ? ASTNodeType.AND : ASTNodeType.OR, null, _curLine);
                }
            }

            ParseExpression(expr, lexemes.Slice(start, lexemes.Length - 1));
        }
Esempio n. 5
0
 private static void ParseValue(ASTNode node, string lexeme, ASTNodeType typeDefault)
 {
     if (lexeme.StartsWith("0x"))
     {
         node.Push(ASTNodeType.SERIAL, lexeme, _curLine);
     }
     else if (int.TryParse(lexeme, out _))
     {
         node.Push(ASTNodeType.INTEGER, lexeme, _curLine);
     }
     else if (double.TryParse(lexeme, out _))
     {
         node.Push(ASTNodeType.DOUBLE, lexeme, _curLine);
     }
     else
     {
         node.Push(typeDefault, lexeme, _curLine);
     }
 }
Esempio n. 6
0
        private static void ParseCommand(ASTNode node, string lexeme)
        {
            // A command may start with an '@' symbol. Pick that
            // off.
            if (lexeme[0] == '@')
            {
                node.Push(ASTNodeType.QUIET, null, _curLine);
                lexeme = lexeme.Substring(1, lexeme.Length - 1);
            }

            // A command may end with a '!' symbol. Pick that
            // off.
            if (lexeme.EndsWith("!"))
            {
                node.Push(ASTNodeType.FORCE, null, _curLine);
                lexeme = lexeme.Substring(0, lexeme.Length - 1);
            }

            node.Push(ASTNodeType.COMMAND, lexeme, _curLine);
        }
Esempio n. 7
0
        private static void ParseOperator(ASTNode node, string lexeme)
        {
            switch (lexeme)
            {
            case "==":
            case "=":
                node.Push(ASTNodeType.EQUAL, null, _curLine);
                break;

            case "!=":
                node.Push(ASTNodeType.NOT_EQUAL, null, _curLine);
                break;

            case "<":
                node.Push(ASTNodeType.LESS_THAN, null, _curLine);
                break;

            case "<=":
                node.Push(ASTNodeType.LESS_THAN_OR_EQUAL, null, _curLine);
                break;

            case ">":
                node.Push(ASTNodeType.GREATER_THAN, null, _curLine);
                break;

            case ">=":
                node.Push(ASTNodeType.GREATER_THAN_OR_EQUAL, null, _curLine);
                break;

            default:
                throw new SyntaxError(node, "Invalid operator in binary expression");
            }
        }
Esempio n. 8
0
        private static void ParseForEachLoop(ASTNode statement, string[] lexemes)
        {
            // foreach X in LIST
            var loop = statement.Push(ASTNodeType.FOREACH, null, _curLine);

            if (lexemes[1] != "in")
            {
                throw new SyntaxError(statement, "Invalid foreach loop");
            }

            // This is the iterator name
            ParseValue(loop, lexemes[0], ASTNodeType.STRING);
            loop.Push(ASTNodeType.LIST, lexemes[2], _curLine);
        }
Esempio n. 9
0
        private static void ParseUnaryExpression(ASTNode node, string[] lexemes)
        {
            var expr = node.Push(ASTNodeType.UNARY_EXPRESSION, null, _curLine);

            int i = 0;

            if (lexemes[i] == "not")
            {
                expr.Push(ASTNodeType.NOT, null, _curLine);
                i++;
            }

            ParseOperand(expr, lexemes[i++]);

            for (; i < lexemes.Length; i++)
            {
                ParseValue(expr, lexemes[i], ASTNodeType.STRING);
            }
        }
Esempio n. 10
0
        private static void ParseStatement(ASTNode node, string[] lexemes)
        {
            var statement = node.Push(ASTNodeType.STATEMENT, null, _curLine);

            // Examine the first word on the line
            switch (lexemes[0])
            {
            // Ignore comments
            case "#":
            case "//":
                return;

            // Control flow statements are special
            case "if":
            {
                if (lexemes.Length <= 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                var t = statement.Push(ASTNodeType.IF, null, _curLine);
                ParseLogicalExpression(t, lexemes.Slice(1, lexemes.Length - 1));
                break;
            }

            case "elseif":
            {
                if (lexemes.Length <= 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                var t = statement.Push(ASTNodeType.ELSEIF, null, _curLine);
                ParseLogicalExpression(t, lexemes.Slice(1, lexemes.Length - 1));
                break;
            }

            case "else":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.ELSE, null, _curLine);
                break;

            case "endif":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.ENDIF, null, _curLine);
                break;

            case "while":
            {
                if (lexemes.Length <= 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                var t = statement.Push(ASTNodeType.WHILE, null, _curLine);
                ParseLogicalExpression(t, lexemes.Slice(1, lexemes.Length - 1));
                break;
            }

            case "endwhile":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.ENDWHILE, null, _curLine);
                break;

            case "for":
            {
                if (lexemes.Length <= 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                ParseForLoop(statement, lexemes.Slice(1, lexemes.Length - 1));
                break;
            }

            case "endfor":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.ENDFOR, null, _curLine);
                break;

            case "break":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.BREAK, null, _curLine);
                break;

            case "continue":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.CONTINUE, null, _curLine);
                break;

            case "stop":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.STOP, null, _curLine);
                break;

            case "replay":
            case "loop":
                if (lexemes.Length > 1)
                {
                    throw new SyntaxError(node, "Script compilation error");
                }

                statement.Push(ASTNodeType.REPLAY, null, _curLine);
                break;

            default:
                // It's a regular statement.
                ParseCommand(statement, lexemes[0]);

                foreach (var lexeme in lexemes.Slice(1, lexemes.Length - 1))
                {
                    ParseValue(statement, lexeme, ASTNodeType.STRING);
                }
                break;
            }
        }