gcc config
[prop.git] / prop-src / parser-util.pcc
blob79b04312484cf1862a5eb618e59bd70853631d35
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 //  This file implements the utility routines for the parser.
4 //
5 ///////////////////////////////////////////////////////////////////////////////
6 #include <new>
7 #include <iostream>
8 #include <AD/pretty/postream.h>
9 #include <strstream.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include "ir.ph"
13 #include "ast.ph"
14 #include "parser.ph"
15 #include "type.h"
16 #include "matchcom.h"
17 #include "keywords.ph"
18 #include "config.h"
19 #include "list.h"
20 #include "compiler.h"
21 #include "options.h"
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 ///////////////////////////////////////////////////////////////////////////////
41 //  Destructor
43 ///////////////////////////////////////////////////////////////////////////////
44 PropParser::~PropParser() {}
46 ///////////////////////////////////////////////////////////////////////////////
48 //  Method to initialize the parser
50 ///////////////////////////////////////////////////////////////////////////////
51 void PropParser::initialize(Compiler& C)
52 {  compiler         = &C;
53    graphtype_def    = 0;
54    SCs_top          = 0;
55    quote_top        = 0;
56    levels_top       = 0;
57    options.emit_code = true;
58    me_top           = 0;
59    var_top          = 0;
60    antecedent_count = 0;
61    in_rewrite       = false;
62    rule_count       = 0;
63    is_view_def      = false;
64    symbol_count     = 0;
65    item_count       = 0;
66    nonterm_count    = 0;
67    code_top         = 0;
68    includes_top     = 0;
69    included_count   = 0;
70    program          = #[];
71    my_cons          = NOcons;
72    my_exp           = NOexp;
73    match_rule       = 0;
74    rw_top           = -1;
75    push_rw_stack();
78 ///////////////////////////////////////////////////////////////////////////////
79 //  Method to push/pop the rw stack
80 ///////////////////////////////////////////////////////////////////////////////
81 void PropParser::push_rw_stack()
82 {  ++rw_top;
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()
90 {  --rw_top;
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), 
118                      head = ps, 
119                      tail = p
120                    }; 
122 Pat mkvecpat
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), 
126                        len       = len, 
127                        array     = array, 
128                        elements  = ps, 
129                        head_flex = flex1, 
130                        tail_flex = flex2
131                      };
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)
137 {  Cons c = NOcons;
139    match (a) and (b)
140    {  IDexp id, RECORDexp _ | c = find_cons(id): { return CONSexp(c,#[],b); }
141    |  _:                                         { return APPexp(a,b); }
142    }
144    match (a) 
145    {  IDexp id | c = find_cons(id): { return CONSexp(c,#[],b); }
146    |  _:                            { return APPexp(a,b); }
147    }
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)
154 {  //match (b)
155    //{  ! DEFVALty _: { b = DEFVALty(b,LITERALexp(INTlit(0))); }
156    //|  _: // skip
157    //}
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 ];
173    }
174    scan.reset();
175    first_line = line;
176    return 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)
193 {  Bool from_current;
194    Exp e = pv_env.lookup(id,&from_current); 
195    match (e) and (id[0])
196    {  NOexp, '$' || '#': 
197       {  error ("%Lpattern variable '%s' has no binding at this point\n", id); 
198          return NOexp;
199       }
200    |  NOexp, _: { return IDexp(id); }
201    |  e,     _: { return e; }
202    }
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];
219       }
220    Pat scheme = DatatypeCompiler::lookup_pat(id);
221    if (scheme != NOpat) {
222       return apply_pat(scheme,NOpat);
223    } else {
224       return IDpat(id,mkvar(),NOexp);
225    }
228 ///////////////////////////////////////////////////////////////////////////////
229 //  Create a pattern from a constructor
230 ///////////////////////////////////////////////////////////////////////////////
231 Pat PropParser::mkconspat(Cons cons)
232 {  match (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);
238             return NOpat;
239          } else
240          {  return lexeme_pattern; } 
241       }
242    |  _: { return CONSpat(cons); }
243    }
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)
251 {  Ty junk_ty = NOty;
252    if (item_number <= 0)
253       pv_env.add(#"$$",SYNexp(0,-symbol_number,NOty,false),junk_ty);
254    else
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());
265       meta.reset();
266    } else if (lexbuf.length() == 0)
267    {  error ("%L%s at end of file, ", message);
268    } else
269    {  error ("%L%s at token \"%s\", ", message, lexbuf.text());
270    }
271    return Retry;
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;
282    SCs_top     = 0;
283    levels_top  = 0;
284    quote_top   = 0;
285    options.emit_code   = true;
286    program     = #[];
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];
300       Loc loc;
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);
306    }
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]);
320    if (new_stream == 0) 
321    {  error ("%Lcan't find include file \"%s\"\n", file_name);
322       return;
323    }
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;
334    includes_top++;
335    line         = 1;
336    first_line   = 1;
337    file         = file_name; 
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");
351    --includes_top;
352    debug_msg("[Closing \"%s\" %i lines]\n", file, line-1);
353    delete input_stream;
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)
386 {  ostrstream b;
387    std::ostream& f = b;
388    f << e << ends;
389    emit(b.str());
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()
410 {  if (SCs_top != 0) 
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()
424 {  levels_top--; }
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);
438       return c;
439    } else
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);
445       }
446       quote_top--;
447       return quote.close;
448    }