aboutsummaryrefslogtreecommitdiff
path: root/calculator-java/src/main/java/ch/bfh/parser/TermParser.java
blob: 5ead5912e61c11a10130698998f52b67351544d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package ch.bfh.parser;

import ch.bfh.lexer.CalculatorLexer;
import ch.bfh.lexer.Token;

class TermParser extends ExpressionParser {

    public TermParser(CalculatorLexer cl, Token lastToken) {
        super(cl, lastToken, false);
    }

    @Override
    protected void parse() {
        Token token = lastToken;
        lastToken = null;
        Parser l = null;
        Parser r = null; // left and right expressions
        Token op = null; // operation of the current l and right expressions

        loop:
        while (token != null && token.type != Token.EOL) {
            switch (token.type) {
                case Token.ADD:
                    if (op != null) {
                        lastToken = token;
                        break loop; // going here on case 'n/+...' or 'n*+...' since '+' would be invalid
                    }
                case Token.SUB:
                case Token.NUM:
                case Token.ID:
                case Token.PAL:
                    if (l == null) {
                        l = new FactorParser(cl, token);
                        this.parsers.add(l);
                        token = l.lastToken;
                        continue loop;
                    } else if (op != null) {
                        r = new FactorParser(cl, token);
                        this.parsers.add(r);
                        token = r.lastToken;
                        lastToken = token; // in case we finished
                        continue loop;
                    } else {
                        lastToken = token;
                        break loop; // going here on case 'n+...' or 'n-...' since '+' and '-' are part of the parent expression
                    }
                case Token.MUL:
                case Token.DIV:
                    if (l != null && op == null) { // if the '*' or '/' signs are between two Factors (op)
                        op = token;
                        this.ops.add(op);
                    } else if (l != null && r != null) { // if we already found a 'l op r' we roll
                        l = r;
                        r = null;
                        op = token;
                        this.ops.add(op);
                    } else
                        throw new ParserException("Two '" + token.str + "' in a row were found.");
                    break;
                case Token.PAR:  // Going as high as possible --> possibly the end of an expression created by a Factor :)
                    lastToken = token;
                    break loop;
                case Token.EQU:
                case Token.LET:
                    throw new ParserException("The inputted token '"+token.str+"' can only be placed in a variable declaration context (let var = Expression).");
                case Token.END:
                    throw new ParserException("The keyword 'exit' can only be placed at the beginning of an expression.");
            }
            token = cl.nextToken();
        }
        if (op != null && r == null)
            throw new ParserException("Missing expression after last operator '" + op.str + "'");
    }

    @Override
    public double getValue() {
        double result = 0.0;
        if (!this.parsers.isEmpty()) {
            result = this.parsers.get(0).getValue();

            for (int i = 1; i < this.parsers.size(); i++) {
                switch (this.ops.get(i - 1).type) {
                    case Token.MUL:
                        result *= this.parsers.get(i).getValue();
                        break;
                    case Token.DIV:
                        result /= this.parsers.get(i).getValue();
                        break;
                }
            }
        }
        return result;
    }
}