Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 59034f656fed899e00cf2f484c45de19c0d93506 (plain) (blame)
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// Generated by Rex version 1.0 alpha 5

package org.eclipse.photran.internal.core.f95modelparser;

import java.util.ArrayList;

/**
 * An LALR(1) parser
 */
public class Parser
{
    /**
     * The lexical analyzer
     */
    protected ILexer lexer;

    /**
     * This becomes set to true when we finish parsing
     */
    protected boolean doneParsing;

    /**
     * This is set to true if parsing finishes prematurely due to a syntax error
     */
    protected boolean error;

    /**
     * The current state of the parser
     */
    protected int currentState;

    /**
     * The next token in the input stream
     */
    protected Token lookaheadToken;

    /**
     * Although textbook descriptions of LR parsers suggest a stack containing
     * both states and symbols (terminals and nonterminals), we maintain three
     * parallel stacks: one for states, one for symbols, and one for values
     * returned by user code.  This one holds symbols (terminals and nonterminals).
     */
    protected ArrayList symbolStack;

    /**
     * Although textbook descriptions of LR parsers suggest a stack containing
     * both states and symbols (terminals and nonterminals), we maintain three
     * parallel stacks: one for states, one for symbols, and one for values
     * returned by user code.  This one holds states.
     */
    protected ArrayList stateStack;

    /**
     * Although textbook descriptions of LR parsers suggest a stack containing
     * both states and symbols (terminals and nonterminals), we maintain three
     * parallel stacks: one for states, one for symbols, and one for values
     * returned by user code.  This one holds these values.  When a reduction
     * is performed and user code like <code>return $1 + $2</code> is executed, this
     * is where the values of $1 and $2 come from.
     */
    protected ArrayList valueStack;

    /**
     * Provides access to an ErrorRecovery object, which attempts to
     * recover from syntax errors via error productions in the grammar
     */
    protected ErrorRecovery errorRecovery;

    /**
     * The userActions field refers to an instance of the ParserUserActions
     * class, which contains all of the user code
     */
    protected AbstractParserAction userActions;

    /**
     * The entrypoint to the parser.
     */
    public Object parse(ILexer lexicalAnalyzer, AbstractParserAction parseAction) throws Exception
    {
        errorRecovery = new ErrorRecovery(this);
        lexer = lexicalAnalyzer;
        userActions = parseAction;
        parsingTable = new ParsingTable(parseAction);

        // Initialize the parsing stacks
        symbolStack = new ArrayList();
        stateStack = new ArrayList();
        valueStack = new ArrayList();

        // Run any user-specified initialization code
        userActions.initialize();

        // The parser starts in state 0
        currentState = 0;
        stateStack.add(new Integer(currentState));
        readNextToken();
        doneParsing = false;
        error = false;

        // Repeatedly determine the next action based on the current state
        while (!doneParsing)
            parsingTable.processLookaheadFor(this);

        // Run any user-specified deinitialization code
        userActions.deinitialize();

        // Return the value from the last piece of user code
        // executed in a completed parse (the value associated with the
        // start symbol), or null if parsing failed.
        return (error || valueStack.isEmpty()) ? null : (Object)valueStack.get(valueStack.size()-1);
    }

    void readNextToken() throws Exception
    {
        lookaheadToken = lexer.yylex();
    }

    /**
     * Shift the next input symbol and change the parser to the given state.
     */
    void shiftAndGoToState(int state) throws Exception
    {
        symbolStack.add(lookaheadToken.getTerminal());
        stateStack.add(new Integer(state));
        valueStack.add(lookaheadToken);
        currentState = state;
        readNextToken();
    }

    /**
     * Reduce the top symbolsToPop symbols on the stack to the given nonterminal,
     * and change the parser state accordingly.  This overload is called when reducing to an
     * ordinary nonterminal.
     */
    void reduce(Nonterminal nonterminalToReduceTo, int symbolsToPop)
    {
        for (int i = 0; i < symbolsToPop; i++)
        {
            symbolStack.remove(symbolStack.size() - 1);
            stateStack.remove(stateStack.size() - 1);
        }
        currentState = ((Integer)stateStack.get(stateStack.size()-1)).intValue();
        symbolStack.add(nonterminalToReduceTo);
        stateStack.add(new Integer(parsingTable.getGoToFor(nonterminalToReduceTo, this)));
        currentState = ((Integer)stateStack.get(stateStack.size()-1)).intValue();
    }

    /**
     * Reduce the top symbolsToPop symbols on the stack to the given nonterminal,
     * and change the parser state accordingly.  This overload is called when reducing to a
     * nonterminal derived from an EBNF expression: these nonterminals push their own values
     * onto the valueStack, and so the reduce method does not need to.
     */
    void reduce(Nonterminal nonterminalToReduceTo, int symbolsToPop, Object nonterminalValue)
    {
        for (int i = 0; i < symbolsToPop; i++)
        {
            symbolStack.remove(symbolStack.size() - 1);
            stateStack.remove(stateStack.size() - 1);
        }
        currentState = ((Integer)stateStack.get(stateStack.size()-1)).intValue();
        symbolStack.add(nonterminalToReduceTo);
        valueStack.add(nonterminalValue);
        stateStack.add(new Integer(parsingTable.getGoToFor(nonterminalToReduceTo, this)));
        currentState = ((Integer)stateStack.get(stateStack.size()-1)).intValue();
    }

    /**
     * Indicate that parsing is complete
     */
    void accept()
    {
        doneParsing = true;
    }

    /**
     * Stop parsing: A syntax error was found
     */
    void syntaxError() throws Exception
    {
        if (errorRecovery.recover()) return;
        doneParsing = true;
        error = true;

        // Run any user-specified syntax error code
        userActions.syntaxError();
        throw new SyntaxError(lookaheadToken);
    }

    /**
     * Retrieve the parser's current lookahead token
     */
    Token getLookaheadToken() { return lookaheadToken; }

    /**
     * Retrieve the parser's symbol stack
     */
    ArrayList getSymbolStack() { return symbolStack; }

    /**
     * Retrieve the parser's state stack
     */
    ArrayList getStateStack() { return stateStack; }

    /**
     * Retrieve the parser's value stack
     */
    ArrayList getValueStack() { return valueStack; }

    /**
     * Retrieve the object containing all of the user code
     */
    AbstractParserAction getUserActions() { return userActions; }

    /**
     * Stores the parsing table
     */
    protected ParsingTable parsingTable;

    /**
     * Retrieve the parser's current state (an integer)
     */
    int getCurrentState() { return currentState; }
}

Back to the top