public BaseExpression Parse(string source)
 {
     var tokenizer = new Tokenizer();
     var tokens = tokenizer.Read(source);
     var queue = new TokensQueue(tokens);
     return Parse(queue);
 }
 public IList<BaseExpression> ParseArguments(TokensQueue tokens)
 {
     var res = new List<BaseExpression>();
     while (!tokens.IsEndOfLine) {
         var preview = tokens.Peek();
         if (preview.Type == TokenType.CloseParenthesis) return res;
         var arg = Parse(tokens);
         res.Add(arg);
         preview = tokens.Peek();
         if (preview.Type != TokenType.Comma) break;
         tokens.Read(TokenType.Comma);
     }
     return res;
 }
 protected BaseExpression ParseLiteral(Token token, TokensQueue queue)
 {
     if (queue.Count > 0) {
         var preview = queue.Peek();
         if (preview.Type == TokenType.OpenParenthesis) {
             return Func(token, queue);
         }
     }
     if (token.StringValue == "$") {
         return new NumberExpression { Value = _context.Offset };
     }
     var lblValue = _context.GetLabel(token);
     if (lblValue == null) {
         throw new TokenException("unknown symbol " + token.StringValue, token);
     }
     return new NumberExpression { Value = (long)lblValue };
 }
 protected BaseExpression Func(Token nameToken, TokensQueue tokens)
 {
     tokens.Read(TokenType.OpenParenthesis);
     var args = ParseArguments(tokens);
     tokens.Read(TokenType.CloseParenthesis);
     switch (nameToken.StringValue.ToLower()) {
         case "low":
             if (args.Count != 1) {
                 throw new TokenException("expected 1 argument", nameToken);
             }
             return new LowByteExpression(args.First());
         case "high":
             if (args.Count != 1) {
                 throw new TokenException("expected 1 argument", nameToken);
             }
             return new HighByteExpression(args.First());
         default:
             throw new TokenException("unknown function " + nameToken.StringValue, nameToken);
     }
 }
 public BaseExpression Parse(TokensQueue tokens)
 {
     return ParseWithPriority(tokens, 0);
 }
 private BaseExpression ProcessBinaryExpression(Token opToken, BaseExpression left, TokensQueue tokens)
 {
     var tokenPriority = GetPriority(opToken.Type);
     var other = ParseWithPriority(tokens, tokenPriority + 1);
     switch (opToken.Type) {
         case TokenType.Plus: return new AddExpression(left, other);
         case TokenType.Minus: return new SubExpression(left, other);
         case TokenType.Multiply: return new MulExpression(left, other);
         case TokenType.Divide: return new DivExpression(left, other);
         case TokenType.Mod: return new ModExpression(left, other);
         case TokenType.LeftShift: return new ShiftLeftExpression(left, other);
         case TokenType.RightShift: return new ShiftRightExpression(left, other);
         case TokenType.BitOr: return new BitOrExpression(left, other);
         case TokenType.BitAnd: return new BitAndExpression(left, other);
         case TokenType.BitXor: return new BitXorExpression(left, other);
         default:
             throw new TokenException("unexpected operator", opToken);
     }
 }
        private BaseExpression ParseWithPriority(TokensQueue tokens, int priority)
        {
            BaseExpression left = ParseOperand(tokens);
            while (tokens.Count > 0) {
                var preview = tokens.Peek();
                switch (preview.Type) {
                    case TokenType.NewLine:
                    case TokenType.Comma:
                    case TokenType.CloseParenthesis:
                        return left;
                }

                var tokenPriority = GetPriority(preview.Type);
                if (tokenPriority >= 0 && tokenPriority < priority) {
                    if (left != null) return left;
                    throw new Exception("some case");
                }

                var token = tokens.Read();
                switch (token.Type) {
                    case TokenType.Plus:
                    case TokenType.Minus:
                    case TokenType.Multiply:
                    case TokenType.Divide:
                    case TokenType.Mod:
                    case TokenType.LeftShift:
                    case TokenType.RightShift:
                    case TokenType.BitOr:
                    case TokenType.BitAnd:
                    case TokenType.BitXor:
                        left = ProcessBinaryExpression(token, left, tokens);
                        break;
                    default:
                        throw new TokenException("unexpected token " + token.StringValue, token);
                }
            }

            return left;
        }
        private BaseExpression ParseOperand(TokensQueue tokens)
        {
            if (tokens.IsEndOfLine) {
                throw new TokenException("operand expected", tokens.LastReadToken);
            }

            var token = tokens.Read();
            switch (token.Type) {
                case TokenType.Integer: return new NumberExpression { Value = token.IntegerValue };
                case TokenType.Literal: return ParseLiteral(token, tokens);
                case TokenType.NewLine: throw new TokenException("value expected", token);
                case TokenType.Minus: return new NegateExpression(ParseOperand(tokens));
                case TokenType.OpenParenthesis:
                    var inner = Parse(tokens);
                    if (tokens.IsEndOfLine) {
                        throw new TokenException("missing closing parenthesis", tokens.LastReadToken);
                    }
                    tokens.Read(TokenType.CloseParenthesis);
                    return inner;
                default:
                    throw new TokenException("unexpected token " + token.StringValue, token);
            }
        }