3 // ADLib, Prop and their related set of tools and documentation are in the
4 // public domain. The author(s) of this software reserve no copyrights on
5 // the source code and any code generated using the tools. You are encouraged
6 // to use ADLib and Prop to develop software, in both academic and commercial
7 // settings, and are free to incorporate any part of ADLib and Prop into
10 // Although you are under no obligation to do so, we strongly recommend that
11 // you give away all software developed using our tools.
13 // We also ask that credit be given to us when ADLib and/or Prop are used in
14 // your programs, and that this notice be preserved intact in all the source
17 // This software is still under development and we welcome any suggestions
18 // and help from the users.
22 //////////////////////////////////////////////////////////////////////////////
27 #include <AD/automata/lrparser.h>
28 #include <AD/contain/stack.h>
29 #include <AD/strings/charesc.h>
31 //////////////////////////////////////////////////////////////////////////////
33 // Make hidden types visible
35 //////////////////////////////////////////////////////////////////////////////
36 typedef LR1Parser::Symbol Symbol
;
37 typedef LR1Parser::ShortSymbol ShortSymbol
;
38 typedef LR1Parser::State State
;
39 typedef LR1Parser::Offset Offset
;
40 typedef LR1Parser::Rule Rule
;
41 typedef LR1Parser::ProductionLength ProductionLength
;
43 //////////////////////////////////////////////////////////////////////////////
45 // Constructor and destructor
47 //////////////////////////////////////////////////////////////////////////////
48 LR1Parser:: LR1Parser( const Offset base_table
[],
49 const State check_table
[],
50 const State def_table
[],
51 const State defact_table
[],
52 const State next_table
[],
53 const ProductionLength len_table
[],
54 const ProductionLength ncount_table
[],
55 const ShortSymbol lhs_table
[],
56 const unsigned short equiv_table
[],
61 : LR1(base_table
,check_table
,def_table
,defact_table
,next_table
,
62 len_table
,ncount_table
,lhs_table
,equiv_table
),
63 error_token(error
), max_terminal(max_term
),
64 max_non_terminal(max_nonterm
), error_status(0) {}
66 LR1Parser::~LR1Parser() {}
68 //////////////////////////////////////////////////////////////////////////////
70 // Default parsing actions
72 //////////////////////////////////////////////////////////////////////////////
73 void LR1Parser::accept() {}
74 void LR1Parser::parser_prefix() {}
75 void LR1Parser::parser_suffix() {}
76 void LR1Parser::adjust_stack(int) {}
77 LR1Parser::ErrorAction
LR1Parser::error_report(const char * message
)
78 { cerr
<< message
<< '\n';
82 //////////////////////////////////////////////////////////////////////////////
84 // Error repair method. We'll just repeatedly discard input tokens until
85 // we reach a point when a non-error transition can be performed.
87 //////////////////////////////////////////////////////////////////////////////
88 LR1Parser::ErrorAction
LR1Parser::error_repair(ParserState
& P
)
90 // Pop state stack until a state that shifts <error> is found.
92 ErrorAction my_action
= error_report("parse error");
97 { new_state
= go(P
.state
,error_token
);
98 //cerr << "[state = " << P.state << "]";
99 if (new_state
!= error_state
&&
100 (isShift(new_state
) || isShiftReduce(new_state
)))
101 goto REPAIR_STATE_FOUND
;
102 if (P
.top
== 0) goto REPAIR_STATE_NOT_FOUND
;
104 State old_state
= P
.state_stack
[--P
.top
];
105 Bool pop_semantic_stack
= true;
106 for (Symbol c
= EOF
; c
<= max_terminal
; c
++)
107 { State delta
= go(old_state
, c
);
108 if (delta
!= error_state
&&
109 ((isShift(delta
) && delta
== P
.state
) ||
110 (isShiftReduce(delta
) && state_of(delta
) == P
.state
)))
111 { pop_semantic_stack
= false; break; }
113 if (pop_semantic_stack
)
114 { // cerr << "[pop stack]";
117 // else { cerr << "[don't pop stack]"; }
122 // Shift to the new state after <error>
123 //cerr << "Repair state = " << new_state << '\n';
124 if (isShift(new_state
))
125 { // shift to new state
126 P
.state_stack
[P
.top
++] = P
.state
;
128 } else if (isShiftReduce(new_state
))
129 { // shift to new state, then reduce immediately
130 P
.state_stack
[P
.top
++] = P
.state
;
131 P
.state
= state_of(new_state
);
132 new_state
= defact
[P
.state
];
133 Rule rule
= reduceRule(new_state
);
134 adjust_stack(-ncount
[rule
]);
135 int length
= len
[rule
];
136 if (length
> 0) { P
.top
-= length
; P
.state
= P
.state_stack
[P
.top
]; }
137 } else goto REPAIR_ERROR
;
139 // Discard tokens until we find one that doesn't cause an error.
141 { Symbol token
= P
.token_count
> 0 ? P
.token_stack
[--P
.token_count
]
143 new_state
= go(P
.state
, token
);
144 if (new_state
!= error_state
)
145 { P
.token_stack
[P
.token_count
++] = token
;
148 if (token
== EOF
) goto REPAIR_NOT_POSSIBLE
;
149 //cerr << "[Discarding " << token << "]";
154 REPAIR_STATE_NOT_FOUND
:
155 // error_report("Syntax error");
158 // error_report("Syntax error(no repair possible)");
161 // error_report("Syntax error(error in repair)");
165 //////////////////////////////////////////////////////////////////////////////
167 // Default symbol printing method. Should be redefined by user.
169 //////////////////////////////////////////////////////////////////////////////
170 void LR1Parser::print_symbol(ostream
& f
, Symbol S
)
171 { if (S
< 0) f
<< "<eof>";
172 else if (S
< 256) f
<< '\'' << print_char((char)S
) << '\'';
173 else if (S
<= max_terminal
) print_user_symbol(f
,S
);
174 else f
<< "[token " << (int)S
<< "]";
177 void LR1Parser::print_user_symbol(ostream
& f
, Symbol S
)
178 { f
<< "[token " << (int)S
<< "]"; }
180 //////////////////////////////////////////////////////////////////////////////
182 // Default method does not explain anything
184 //////////////////////////////////////////////////////////////////////////////
185 void LR1Parser::explain_error()
189 //////////////////////////////////////////////////////////////////////////////
191 // This method prints out the expected tokens.
193 //////////////////////////////////////////////////////////////////////////////
194 void LR1Parser::nice_explain(ostream
& f
)
197 for (Symbol c
= 0; c
<= max_terminal
; c
++)
198 { State delta
= go(error_status
->state
, c
);
199 if (delta
!= error_state
)
200 { // if (isShift(delta) || isShiftReduce(delta))
201 { print_symbol(f
,c
); f
<< ' '; }
206 //////////////////////////////////////////////////////////////////////////////
208 // This method explains things in great detail.
210 //////////////////////////////////////////////////////////////////////////////
211 void LR1Parser::debug_explain(ostream
& f
)
212 { if (error_status
== 0) return;
216 for (j
= error_status
->token_count
- 1; j
>= 0; j
--)
217 { print_symbol(f
,error_status
->token_stack
[j
]); f
<< " "; }
219 f
<< "\nState stack: ";
220 for (j
= error_status
->top
- 1; j
>= 0; j
--)
221 { f
<< "<" << error_status
->state_stack
[j
] << "> "; }
223 f
<< "\nAt state <" << error_status
->state
<< ">:\n";
225 Bool one_reduce
= defact
[error_status
->state
];
227 for (Symbol c
= 0; c
<= max_non_terminal
; c
++)
228 { State delta
= go(error_status
->state
, c
);
229 if (delta
!= error_state
)
230 { if (isShift(delta
))
231 { f
<< "\tOn "; print_symbol(f
,c
);
232 f
<< " shift, and goto state <" << delta
<< ">\n";
233 } else if (isShiftReduce(delta
))
234 { f
<< "\tOn "; print_symbol(f
,c
);
235 Rule r
= reduceRule(defaultAction(state_of(delta
)));
236 f
<< " shift, goto state <" << state_of(delta
)
237 << "> and reduce using rule {" << r
238 << "}, lhs = " << lhs
[r
];
239 f
<< " length = " << reduceLen(r
) << "\n";
240 } else if (! one_reduce
)
241 { f
<< "\tOn "; print_symbol(f
,c
);
242 Rule r
= reduceRule(delta
);
243 f
<< " reduce using rule {" << r
244 << "}, lhs = " << lhs
[r
];
245 f
<< " length = " << reduceLen(r
) << "\n";
250 { Rule r
= reduceRule(one_reduce
);
251 f
<< "\tOn <default> reduce using rule {"
252 << reduceRule(one_reduce
)
253 << "}, lhs = " << lhs
[r
];
254 f
<< " length = " << reduceLen(r
) << "\n";
256 if (error_status
->token_count
> 0)
257 { Symbol token
= error_status
->token_stack
[error_status
->token_count
-1];
258 State new_state
= go(error_status
->state
,token
);
259 f
<< "\tToken = "; print_symbol(f
,token
);
260 f
<< "(" << token
<< ", equiv = " << equiv_classes
[token
-EOF
] << ")";
261 f
<< " new state = " << new_state
<< "\n";
262 f
<< "\tMax_non_terminal = " << max_non_terminal
<< "\n";
263 f
<< "\tMax_terminal = " << max_terminal
<< "\n";