Console calculator Part 2 : The Parser

ddanbe 0 Tallied Votes 1K Views Share

Here is the second piece of code.
The parser tries to interpret the tokens it gets from the scanner.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleCalculator
{
    class Parser : Scanner   
    {
        /// <summary>
        /// Parser class, inherits from Scanner class
        /// Each method (except contructor) assumes that get_token has been called.
        /// It means that curr_tok holds the next token to be analysed.
        /// </summary>

        /// <summary>
        /// Parser custom default constructor.
        /// Defines two mathematical "constants".
        /// </summary>
        public Parser()
        {
            SymbolTable.Add("pi", Math.PI);
            SymbolTable.Add("e", Math.E);
        }

        //some things are done here, no more loop
        public double prim()
        {
            switch (curr_tok)
            {
                case token_value.NAME:
                    if (get_token() == token_value.ASSIGN)
                    {
                        string remember = name_string; //get_token might change name_string
                        curr_tok = get_token();
                        number_value = expr();
                        if (!SymbolTable.ContainsKey(remember))
                        {
                            SymbolTable.Add(remember, number_value);
                        }
                        else
                        {
                            SymbolTable[remember] = number_value;
                        }
                        return number_value;
                    }
                    if (SymbolTable.TryGetValue(name_string, out number_value))
                    {
                        return number_value;
                    }
                    return number_value;
                case token_value.NUMBER:
                    curr_tok = get_token();
                    return number_value;
                case token_value.MINUS: //unary minus
                    curr_tok = get_token();
                    return -prim();
                case token_value.LPAREN:
                    curr_tok = get_token();
                    double e = expr();
                    if (curr_tok != token_value.RPAREN) { Error(") expected"); return 0.0; }
                    curr_tok = get_token();
                    return e;
                case token_value.SQRT:
                    if (FindLeftParentesis())
                    {
                        curr_tok = get_token();
                        double f = expr();
                        if (curr_tok != token_value.RPAREN) { Error(") expected"); return 0.0; }
                        curr_tok = get_token();
                        if (f >= 0.0)
                        {
                            return Math.Sqrt(f);
                        }
                        else
                        {
                            Error("A square root of a negative is not possible.");
                        }
                    }
                    Error("Bad function syntax"); return 0.0;
                default:
                    Error("primary expected");
                    return 0.0;
            }
        }

        //handles multiplication and division
        public double term()
        {
            double left = prim();
            for (; ; )             //"for ever" and to avoid error "not all code paths return a value"
                switch (curr_tok)
                {
                    case token_value.MUL:
                        curr_tok = get_token();
                        left *= prim();
                        break;
                    case token_value.DIV:
                        curr_tok = get_token();
                        double d = prim();
                        if (d == 0) { Error("Divide by 0"); return double.NaN; }
                        left /= d;
                        break;
                    default:
                        return left;
                }
        }

        //handles addition and sustraction
        public double expr()
        {
            double left = term();
            for( ; ; )            //"for ever" and to avoid error "not all code paths return a value"
                switch (curr_tok)
                {
                    case token_value.PLUS:
                        curr_tok = get_token();
                        left += term();
                        break;
                    case token_value.MINUS:
                        curr_tok = get_token();
                        left -= term();
                        break;
                    default:
                        return left;
                }
        }
    }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.