3 * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
24 public errordomain Valadoc
.ParserError
{
29 public class Valadoc
.Parser
: ParserCallback
{
31 public Parser (Settings settings
, Scanner scanner
, ErrorReporter reporter
) {
36 TokenType
.init_token_types ();
39 private Settings _settings
;
40 private Scanner _scanner
;
41 private ErrorReporter _reporter
;
42 private Rule _root_rule
;
44 private string _filename
;
45 private int _first_line
;
46 private int _first_column
;
47 private Token _current_token
;
49 private Vala
.ArrayList
<Rule
> rule_stack
= new Vala
.ArrayList
<Rule
> ();
50 private Vala
.ArrayList
<Object?
> rule_state_stack
= new Vala
.ArrayList
<Object?
> ();
52 public void set_root_rule (Rule root_rule
) {
53 _root_rule
= root_rule
;
56 public void parse (string content
, string filename
, int first_line
, int first_column
)
60 _first_line
= first_line
;
61 _first_column
= first_column
;
64 rule_state_stack
.clear ();
67 push_rule (_root_rule
);
69 _scanner
.scan (content
);
72 if (rule_stack
.size
!= 0) {
73 error (null, "Rule stack is not empty!");
75 } catch (ParserError e
) {
77 log_error (e
.message
);
79 // Set an in_error boolean, try to recover
80 // And only throw the error at the end of parse ?
85 public void accept_token (Token token
) throws ParserError
{
87 debug ("Incomming token: %s", token
.to_pretty_string ());
90 _current_token
= token
;
91 int rule_depth
= rule_stack
.size
;
92 Rule
.Forward forward
= Rule
.Forward
.NONE
;
93 Rule? rule
= peek_rule ();
95 throw new ParserError
.INTERNAL_ERROR ("Rule stack is empty!");
97 while (rule
!= null) {
98 if (rule
.accept_token (token
, this
, forward
)) {
102 // Check for invalid recursion
103 if (rule_depth
!= rule_stack
.size
&& peek_rule () == rule
) {
104 error (null, "Parser state error");
109 // Rule stack size have changed
110 // Check for propagation
111 forward
= rule_depth
> rule_stack
.size ? Rule
.Forward
.CHILD
112 : Rule
.Forward
.PARENT
;
113 rule_depth
= rule_stack
.size
;
117 private Rule?
peek_rule (int offset
= -1) {
119 if (rule_stack
.size
+ offset
< 0) {
122 return rule_stack
.get (rule_stack
.size
+ offset
);
125 private Rule
pop_rule () {
126 int last_index
= rule_stack
.size
- 1;
127 Rule rule
= rule_stack
.get (last_index
);
128 rule_stack
.remove_at (last_index
);
129 rule_state_stack
.remove_at (last_index
);
133 public void push_rule (Rule rule
) {
134 rule_stack
.add (rule
);
135 rule_state_stack
.add (null);
138 debug ("Pushed at %2d: %s", rule_stack
.size
- 1, rule
.to_string (null));
142 private Object?
peek_state (int offset
= -1) {
144 if (rule_state_stack
.size
+ offset
< 0) {
147 return rule_state_stack
.get (rule_state_stack
.size
+ offset
);
150 public Object?
get_rule_state () {
151 return peek_state ();
154 public void set_rule_state (Object state
) {
155 int last_index
= rule_stack
.size
- 1;
156 rule_state_stack
.set (last_index
, state
);
159 public void reduce () {
163 Rule? parent_rule
= peek_rule ();
164 if (parent_rule
!= null) {
165 debug ("Reduced to %2d: %s", rule_stack
.size
- 1,
166 parent_rule
.to_string (peek_state ()));
171 public bool would_parent_accept_token (Token token
) {
173 Rule? parent_rule
= peek_rule (offset
);
174 Object? state
= peek_state (offset
);
175 while (parent_rule
!= null) {
177 debug ("WouldAccept - Offset %d; Index %d: %s", offset
,
178 rule_stack
.size
+ offset
, parent_rule
.to_string (state
));
180 if (parent_rule
.would_accept_token (token
, state
)) {
182 debug ("WouldAccept - Yes");
186 if (!parent_rule
.would_reduce (token
, state
)) {
188 debug ("WouldAccept - No");
193 parent_rule
= peek_rule (offset
);
194 state
= peek_state (offset
);
197 debug ("WouldAccept - No");
202 public bool would_parent_reduce_to_rule (Token token
, Rule rule
) {
204 Rule? parent_rule
= peek_rule (offset
);
205 Object? state
= peek_state (offset
);
206 while (parent_rule
!= null) {
208 debug ("WouldReduce - Offset %d; Index %d: %s", offset
,
209 rule_stack
.size
+ offset
, parent_rule
.to_string (state
));
211 if (!parent_rule
.would_reduce (token
, state
)) {
215 parent_rule
= peek_rule (offset
);
216 state
= peek_state (offset
);
218 if ((parent_rule
!= null && parent_rule
.would_accept_token (token
, state
))
219 || (parent_rule
== null && TokenType
.EOF
.matches (token
))) {
221 debug ("WouldReduce - Yes");
226 debug ("WouldReduce - No");
231 public void warning (Token? token
, string message
) {
232 string error_message
;
235 error_message
= message
+ ": " + token
.to_pretty_string ();
237 error_message
= message
;
240 _reporter
.warning (_filename
,
242 get_start_column (token
),
243 get_end_column (token
),
244 _scanner
.get_line_content (),
248 public void error (Token? token
, string message
) throws ParserError
{
249 string error_message
;
252 error_message
= message
+ ": " + token
.to_pretty_string ();
254 error_message
= message
;
257 _reporter
.error (_filename
,
259 get_start_column (token
),
260 get_end_column (token
),
261 _scanner
.get_line_content (),
264 throw new ParserError
.UNEXPECTED_TOKEN (error_message
);
267 private int get_line (Token? token
) {
269 token
= _current_token
;
271 return token
.begin
.line
+ _first_line
;
274 private int get_start_column (Token? token
) {
276 token
= _current_token
;
278 if (token
.begin
.line
== 0) {
279 return token
.begin
.column
+ _first_column
+ 1;
281 return token
.begin
.column
+ 1;
285 private int get_end_column (Token? token
) {
287 token
= _current_token
;
289 if (token
.end
.line
== 0) {
290 return token
.end
.column
+ _first_column
+ 1;
292 return token
.end
.column
+ 1;
297 private void log_error (string message
) {
298 stderr
.printf ("An error occured while parsing: %s\n", message
);
299 stderr
.printf ("\nDumping rule stack:\n");
300 for (int i
= 0; i
< rule_stack
.size
; i
++) {
301 stderr
.printf ("\t%2d: %s\n", i
, rule_stack
[i
].to_string (rule_state_stack
[i
]));