1 ///////////////////////////////////////////////////////////////////////////////
3 // This file implements the utility routines for the parser.
5 ///////////////////////////////////////////////////////////////////////////////
8 #include <AD/pretty/postream.h>
17 #include "keywords.ph"
23 ///////////////////////////////////////////////////////////////////////////////
25 // Explaination mechanism for parser error.
27 ///////////////////////////////////////////////////////////////////////////////
28 instantiate datatype PropToken;
30 void PropParser::print_user_symbol(std::ostream& f, Symbol c)
31 { f << '"' << (PropToken)c << '"'; }
33 void PropParser::explain_error()
34 { nice_explain(cerr); cerr << '\n';
35 if (options.debug) debug_explain(cerr);
38 extern int match_rule;
39 ///////////////////////////////////////////////////////////////////////////////
43 ///////////////////////////////////////////////////////////////////////////////
44 PropParser::~PropParser() {}
46 ///////////////////////////////////////////////////////////////////////////////
48 // Method to initialize the parser
50 ///////////////////////////////////////////////////////////////////////////////
51 void PropParser::initialize(Compiler& C)
57 options.emit_code = true;
78 ///////////////////////////////////////////////////////////////////////////////
79 // Method to push/pop the rw stack
80 ///////////////////////////////////////////////////////////////////////////////
81 void PropParser::push_rw_stack()
83 if (rw_top >= MAX_LEXICAL_DEPTH) bug("rw stack overflow");
84 rw_stack[rw_top].mode = MatchRuleInfo::BOTTOMUP;
85 rw_stack[rw_top].option = MatchRuleInfo::NO_OPTIONS;
86 rw_stack[rw_top].qual = QUALnone;
89 void PropParser::pop_rw_stack()
91 if (rw_top < 0) bug("rw stack underflow");
94 ///////////////////////////////////////////////////////////////////////////////
95 // Functions to mark a tree with the current location.
96 ///////////////////////////////////////////////////////////////////////////////
97 Pat mark(Pat p) { p = MARKEDpat(Loc(),p); return p; }
98 Exp mark(Exp e) { e = MARKEDexp(Loc(),e); return e; }
99 Decl mark(Decl d) { if (d != NOdecl) d = MARKEDdecl(Loc(),d); return d; }
101 ///////////////////////////////////////////////////////////////////////////////
103 // Function to mark tuples used
105 ///////////////////////////////////////////////////////////////////////////////
106 void mark_tuple_used (int arity)
107 { if (arity <= 1 || arity > MAX_TUPLE_ARITY)
108 { bug("Illegal tuple arity: %i", arity); }
109 Used::tuple[arity] = true;
112 ///////////////////////////////////////////////////////////////////////////////
113 // Functions to build lists.
114 ///////////////////////////////////////////////////////////////////////////////
115 Pat mklistpat(Id cons, Id nil, Pats ps, Pat p = NOpat)
116 { return LISTpat''{ cons = lookup_cons(cons),
117 nil = lookup_cons(nil),
123 (Id a, Pat len, Pat array, Pats ps, Bool flex1 = false, Bool flex2 = false)
124 { Used::vector = true;
125 return VECTORpat''{ cons = lookup_cons(a),
133 Exp mklistexp(Id cons, Id nil, Exps es, Exp e = NOexp)
134 { return LISTexp(lookup_cons(cons), lookup_cons(nil), es, e);
136 Exp mkappexp(Exp a, Exp b)
140 { IDexp id, RECORDexp _ | c = find_cons(id): { return CONSexp(c,#[],b); }
141 | _: { return APPexp(a,b); }
145 { IDexp id | c = find_cons(id): { return CONSexp(c,#[],b); }
146 | _: { return APPexp(a,b); }
149 Exp mkvecexp(Id vec, Exps es)
150 { Used::vector = true;
151 return VECTORexp(lookup_cons(vec), es);
153 TermDef mklistterm(Id c, Ty a, Ty b, Decls d)
155 //{ ! DEFVALty _: { b = DEFVALty(b,LITERALexp(INTlit(0))); }
158 return TERMdef''{ id = c, ty = mktuplety(#[ a, b ]), decls = d };
161 Exp extupleexp(Exps es) { mark_tuple_used(length(es)); return EXTUPLEexp(es); }
162 Pat extuplepat(Pats ps) { mark_tuple_used(length(ps)); return EXTUPLEpat(ps); }
163 Ty extuplety(Tys ts) { mark_tuple_used(length(ts));
164 return TYCONty(EXTUPLEtycon,ts); }
166 ///////////////////////////////////////////////////////////////////////////////
167 // Function to build a piece of verbatim code.
168 ///////////////////////////////////////////////////////////////////////////////
169 Decls PropParser::mkcode(Decls decls)
170 { if (options.emit_code && scan.length() > 0) {
171 Decl code = OPAQUEdecl(str_pool(scan.text(),scan.length()));
172 decls = #[ mark(code) ... decls ];
179 ///////////////////////////////////////////////////////////////////////////////
181 // Methods to increment the line count
183 ///////////////////////////////////////////////////////////////////////////////
184 void PropParser::count_lines ()
185 { for (const char * p = lexbuf.text(); *p; p++)
186 if (*p == '\n') line++;
189 ///////////////////////////////////////////////////////////////////////////////
190 // Method to lookup an expression from the pattern environment.
191 ///////////////////////////////////////////////////////////////////////////////
192 Exp PropParser::lookup_exp(Id id)
194 Exp e = pv_env.lookup(id,&from_current);
195 match (e) and (id[0])
197 { error ("%Lpattern variable '%s' has no binding at this point\n", id);
200 | NOexp, _: { return IDexp(id); }
201 | e, _: { return e; }
205 ///////////////////////////////////////////////////////////////////////////////
206 // Type variable stack for building polymorphic type schemes.
207 ///////////////////////////////////////////////////////////////////////////////
208 Ty PropParser::lookup_tyvar(Id id)
209 { for (int i = 0; i < var_top; i++)
210 if (var_stack[i] == id) return INDty(id, i);
211 return mkidty(id,#[]);
214 Pat PropParser::lookup_patvar(Id id)
215 { for (int i = 0; i < var_top; i++)
216 if (var_stack[i] == id) {
217 return pat_stack[i] == NOpat
218 ? (pat_stack[i] = INDpat(id,i,mkvar())) : pat_stack[i];
220 Pat scheme = DatatypeCompiler::lookup_pat(id);
221 if (scheme != NOpat) {
222 return apply_pat(scheme,NOpat);
224 return IDpat(id,mkvar(),NOexp);
228 ///////////////////////////////////////////////////////////////////////////////
229 // Create a pattern from a constructor
230 ///////////////////////////////////////////////////////////////////////////////
231 Pat PropParser::mkconspat(Cons cons)
233 { ONEcons { name, tag, lexeme_pattern,
234 alg_ty = DATATYPEty({ qualifiers ... },_) ... }
235 | (qualifiers & QUALlexeme) && (match_kind[me_top] & MATCHscanner):
236 { if (lexeme_pattern == NOpat)
237 { error ("%Lpattern is undefined for lexeme %s\n",name);
240 { return lexeme_pattern; }
242 | _: { return CONSpat(cons); }
246 ///////////////////////////////////////////////////////////////////////////////
247 // Routine to add a new "$" variable binding
248 ///////////////////////////////////////////////////////////////////////////////
249 void PropParser::add_parse_stack_binding
250 (int item_number, int symbol_number, int nonterm_number)
252 if (item_number <= 0)
253 pv_env.add(#"$$",SYNexp(0,-symbol_number,NOty,false),junk_ty);
255 pv_env.add(#"$" + item_number,
256 SYNexp(nonterm_number,-symbol_number,NOty,false),junk_ty);
259 ///////////////////////////////////////////////////////////////////////////////
260 // Error handler for the parser
261 ///////////////////////////////////////////////////////////////////////////////
262 PropParser::ErrorAction PropParser::error_report(const char * message)
263 { if (meta.length() > 0)
264 { error ("%L%s at quotation text `%s`, ", message, meta.text());
266 } else if (lexbuf.length() == 0)
267 { error ("%L%s at end of file, ", message);
269 { error ("%L%s at token \"%s\", ", message, lexbuf.text());
274 ///////////////////////////////////////////////////////////////////////////////
276 // Method to initialize the lexer
278 ///////////////////////////////////////////////////////////////////////////////
279 void PropParser::initialize_lexer (const char * initial_file_name)
280 { if (initial_file_name == 0) initial_file_name = "<stdin>";
281 file = initial_file_name; line = first_line = 1;
285 options.emit_code = true;
287 levels[levels_top++] = -1;
288 lexbuf.set_context(C);
289 lexbuf.set_stream(*input_stream);
292 ///////////////////////////////////////////////////////////////////////////////
294 // Method to cleanup the lexer
296 ///////////////////////////////////////////////////////////////////////////////
297 void PropParser::cleanup_lexer()
298 { while (quote_top != 0)
299 { const Quote& quote = quote_stack[--quote_top];
301 loc.file_name = quote.file_name;
302 loc.begin_line = quote.line_number;
303 loc.end_line = quote.line_number;
304 error ("%!unbalanced %c ... %c at end of file\n",
305 &loc, (int)quote.open, (int)quote.close);
309 ///////////////////////////////////////////////////////////////////////////////
311 // Method to open a new include file
313 ///////////////////////////////////////////////////////////////////////////////
314 void PropParser::open_include_file(const char * file_name)
315 { for (int i = 0; i < included_count; i++)
316 if (included_files[i] == file_name) return;
317 istream * new_stream = options.open_input_file(file_name);
318 if (options.gen_dependences)
319 IncludeDependency::add_dependency(str_pool[options.current_file_path]);
321 { error ("%Lcan't find include file \"%s\"\n", file_name);
324 if (includes_top >= MAX_INCLUDE_FILES) bug ("Include file stack overflow");
325 if (included_count >= MAX_INCLUDE_FILES) bug ("Too many include files");
326 included_files[included_count++] = file_name;
327 includes[includes_top].file_stream = input_stream;
328 includes[includes_top].file = file;
329 includes[includes_top].line = line;
330 includes[includes_top].first_line = first_line;
331 includes[includes_top].scan = scan;
332 includes[includes_top].doc = doc;
333 includes[includes_top].meta = meta;
338 options.emit_code = false;
339 input_stream = new_stream;
340 lexbuf.push_stream(*input_stream);
341 lexbuf.set_context(C);
344 ///////////////////////////////////////////////////////////////////////////////
346 // Method to open a new include file
348 ///////////////////////////////////////////////////////////////////////////////
349 void PropParser::close_include_file()
350 { if (includes_top <= 0) bug("Include file stack underflow");
352 debug_msg("[Closing \"%s\" %i lines]\n", file, line-1);
354 input_stream = includes[includes_top].file_stream;
355 file = includes[includes_top].file;
356 line = includes[includes_top].line;
357 first_line = includes[includes_top].first_line;
358 scan = includes[includes_top].scan;
359 doc = includes[includes_top].doc;
360 meta = includes[includes_top].meta;
361 options.emit_code = includes_top == 0;
362 input_stream = &lexbuf.pop_stream();
365 ///////////////////////////////////////////////////////////////////////////////
367 // Methods to append text to the code buffer.
369 ///////////////////////////////////////////////////////////////////////////////
370 void PropParser::emit ()
371 { emit(lexbuf.text(), lexbuf.length()); }
373 void PropParser::emit (const char * t, long len)
374 { if (options.emit_code) scan.emit(t,len); }
376 void PropParser::emit (char c)
377 { if (options.emit_code) scan.emit(c); }
379 void PropParser::emit_header ()
380 { if (options.emit_code)
381 compiler->emit_header(lexbuf.text()+2,lexbuf.length()-2);
384 // Append an expression
385 void PropParser::emit(Exp e)
390 b.rdbuf()->freeze(0); // free buffer
393 // Append a constructor expression
394 void PropParser::emit_cons(Id cons_name)
395 { lookup_cons(cons_name);
396 emit(mangle(cons_name));
399 ///////////////////////////////////////////////////////////////////////////////
401 // Methods to enter/exit a lexical context.
403 ///////////////////////////////////////////////////////////////////////////////
404 void PropParser::start_sc(LexicalContext c)
405 { SCs[SCs_top++] = LexicalContext(lexbuf.context()); lexbuf.set_context(c);
406 // if (options.debug) cerr << "[+context " << c << "]";
409 void PropParser::end_sc()
411 { --SCs_top; lexbuf.set_context(SCs[SCs_top]); }
412 // if (options.debug) cerr << "[-context " << SCs[SCs_top] << "]";
415 ///////////////////////////////////////////////////////////////////////////////
417 // Methods to enter/exit a statement
419 ///////////////////////////////////////////////////////////////////////////////
420 void PropParser::start_statement()
421 { levels[levels_top++] = quote_top; start_sc(C); }
423 void PropParser::end_statement()
426 ///////////////////////////////////////////////////////////////////////////////
428 // Methods to push and pop from the quotation stack
430 ///////////////////////////////////////////////////////////////////////////////
431 void PropParser::start_quote(char a, char b)
432 { quote_stack[quote_top++] = Quote(file,line,a,b);
435 char PropParser::end_quote(char c)
436 { if (quote_top == 0)
437 { error("%Lunmatched ending quote %c\n",c);
440 { const Quote& quote = quote_stack[quote_top-1];
441 if (quote.close != c)
442 { error("%Lexpecting %c ... %c (from line %i) but found %c ... %c instead\n",
443 (int)quote.open, (int)quote.close, quote.line_number,
444 (int)quote.open, (int)c);