source: git/ppcc/src/parser.cc @ aa4d31

jengelh-datetimespielwiese
Last change on this file since aa4d31 was aa4d31, checked in by Reimer Behrends <behrends@…>, 4 years ago
parallel preprocessor-related fixes.
  • Property mode set to 100644
File size: 14.7 KB
Line 
1#include "adlib/lib.h"
2#include "adlib/map.h"
3#include "adlib/set.h"
4#include "pplex.h"
5
6#ifdef GCC
7#define noinline __attribute__((noinlinex))
8#else
9#define noinline
10#endif
11
12typedef Map<Str *, Str *> Dict;
13
14static Token space, semicolon, eof, static_token, asterisk;
15static Str *decl_var;
16static Str *decl_extern_var;
17static Str *decl_static_var;
18static StrArr *init_list;
19static Dict *class_vars;
20static Dict *class_types;
21static StrSet *type_prefix_set;
22static Dict *namespaced;
23
24enum DeclType {
25  ExternDecl,
26  StaticDecl,
27  NormalDecl
28};
29
30INIT(DeclParser, {
31  GCVar(space, Token(SymWS, S(" ")));
32  GCVar(semicolon, Token(SymWS, S(";\n")));
33  GCVar(eof, Token(SymEOF, S("")));
34  GCVar(asterisk, Token(SymAst, S("*")));
35  GCVar(static_token, Token(SymIdent, S("static")));
36  GCVar(decl_var, S("__thread"));
37  GCVar(decl_extern_var, S("extern __thread"));
38  GCVar(decl_static_var, S("static __thread"));
39  GCVar(init_list, A());
40  GCVar(class_vars, new Dict());
41  GCVar(class_types, new Dict());
42  GCVar(type_prefix_set, new StrSet());
43  type_prefix_set->add(S("class"));
44  type_prefix_set->add(S("struct"));
45  type_prefix_set->add(S("typedef"));
46  // special treatment for some gfanlib variables for now.
47  GCVar(namespaced, new Dict());
48  namespaced->add(S("MVMachineIntegerOverflow"), S("gfan"));
49  namespaced->add(S("lpSolver"), S("gfan"));
50});
51
52struct State {
53  Int pos, marker;
54};
55
56class Parser : public GC {
57public:
58  TokenList *input, *output;
59  SourceFile *source;
60  Int pos, marker;
61  Int init_count;
62  noinline Parser(SourceFile *_source) {
63    source = _source;
64    input = _source->tokens;
65    if (input->len() == 0 || input->last().sym != SymEOF)
66      input->add(eof);
67    output = new TokenList();
68    pos = 0;
69    marker = 0;
70  }
71  bool c_source() {
72    return source->filename->ends_with(".c");
73  }
74  void skip_until(Word64 syms) {
75    syms |= BIT(SymEOF);
76    while (!TEST(syms, input->at(pos).sym)) {
77      pos++;
78    }
79  }
80  void skip_while(Word64 syms) {
81    while (TEST(syms, input->at(pos).sym)) {
82      pos++;
83    }
84  }
85  noinline Int find_back_until(Word64 syms) {
86    Int p = pos;
87    while (p > marker) {
88      p--;
89      if (TEST(syms, input->at(p).sym))
90        return p;
91    }
92    return p;
93  }
94  noinline void safe_skip_until(Word64 syms) {
95    // handle parentheses and brackets properly.
96    Int par_level = 0;
97    Int brkt_level = 0;
98    Int brace_level = 0;
99    for (;;) {
100      Symbol sym = input->at(pos).sym;
101      switch (sym) {
102        case SymEOF:
103          return;
104        case SymLPar:
105          par_level++;
106          break;
107        case SymRPar:
108          par_level--;
109          break;
110        case SymLBrkt:
111          brkt_level++;
112          break;
113        case SymRBrkt:
114          brkt_level--;
115          break;
116        case SymLBrace:
117          brace_level++;
118          break;
119        case SymRBrace:
120          brace_level--;
121          break;
122        default:
123          if (par_level + brkt_level + brace_level > 0)
124            break;
125          if (TEST(syms, sym)) {
126            return;
127          }
128          break;
129      }
130      advance();
131    }
132  }
133  void skipWhiteSpace() {
134    while (BIT(input->at(pos).sym) & SymsWS) {
135      pos++;
136    }
137  }
138  void advance() {
139    if (pos < input->len())
140      pos++;
141  }
142  Token &token(Int i) {
143    return input->at(i);
144  }
145  TokenList *tokenRange(Int start, Int end) {
146    return input->subarr(start, end - start);
147  }
148  Token &current() {
149    return input->at(pos);
150  }
151  Token &next() {
152    return input->at(pos+1);
153  }
154  Symbol current_sym() {
155    return input->at(pos).sym;
156  }
157  void emit(Token token) {
158    output->add(token);
159  }
160  void emit_gen(Str *s) {
161    output->add(Token(SymGen, s));
162  }
163  void mark() {
164    marker = pos;
165  }
166  Int current_pos() {
167    return pos;
168  }
169  Int markerPos() {
170    return marker;
171  }
172  noinline void push_marked_until(Int p) {
173    while (marker < p) {
174      output->add(input->at(marker));
175      marker++;
176    }
177  }
178  noinline void emit_range(Int start, Int end) {
179    while (start < end) {
180      output->add(input->at(start));
181      start++;
182    }
183  }
184  void emit_tokens(TokenList *tokens) {
185    output->add(tokens);
186  }
187  void push_marked() {
188    push_marked_until(pos);
189  }
190  State save() {
191    State result;
192    result.pos = pos;
193    result.marker = marker;
194    return result;
195  }
196  void restore(State state) {
197    pos = state.pos;
198    marker = state.marker;
199  }
200};
201
202bool IsLiteral(Parser *parser, Int start, Int end) {
203  Int op = 0;
204  Int lit = 0;
205  for (Int i = start; i < end; i++) {
206    Token &token = parser->token(i);
207    switch (token.sym) {
208      case SymWS:
209      case SymEOL:
210      case SymComment:
211        break;
212      case SymOp:
213        if (token.str->eq("-") || token.str->eq("+"))
214          op++;
215        else
216          return false;
217        break;
218      case SymLiteral:
219        lit++;
220        break;
221      default:
222        return false;
223    }
224  }
225  return lit >= 1 && op <= 1;
226}
227
228void EmitDecl(Parser *parser, Str *storage_class,
229    Int type_start, Int type_end,
230    Int var_start, Int var_end,
231    Int init_start, Int init_end, Int var_pos,
232    bool is_class, bool is_toplevel, DeclType decl_type) {
233  bool is_static = (decl_type == StaticDecl);
234  bool is_extern = (decl_type == ExternDecl);
235  parser->emit(Token(SymGen, storage_class));
236  parser->emit(space);
237  parser->emit_range(type_start, type_end);
238  parser->emit(space);
239  if (is_class)
240    parser->emit(asterisk);
241  Str *var_name = parser->token(var_pos).str;
242  parser->emit_range(var_start, var_pos);
243  parser->emit(Token(SymGen, var_name));
244  parser->emit_range(var_pos+1, var_end);
245  if (is_static && !is_class && IsLiteral(parser, init_start+1, init_end)) {
246      parser->emit(space);
247      parser->emit_range(init_start, init_end);
248      parser->emit(semicolon);
249      return;
250  }
251  parser->emit(semicolon);
252  if (is_class) {
253    class_vars->add(var_name, S("(*")->add(var_name)->add(")"));
254    class_types->add(var_name, parser->token(type_start).str);
255  }
256  if ((is_class && !is_extern) || init_start >= 0) {
257    if (is_toplevel) {
258      init_list->add(var_name);
259    }
260    Token var_init = Token(SymGen, var_name->clone()->add("__INIT__"));
261    parser->emit(static_token);
262    parser->emit(space);
263    parser->emit_range(type_start, type_end);
264    parser->emit(space);
265    parser->emit_range(var_start, var_pos);
266    parser->emit(var_init);
267    parser->emit_range(var_pos+1, var_end);
268    if (init_start >= 0) {
269      parser->emit(space);
270      parser->emit_range(init_start, init_end);
271    }
272    parser->emit(semicolon);
273    if (!is_toplevel && !parser->c_source()) {
274      parser->init_count++;
275      parser->emit(Token(SymGen, S(
276        "void pSingular_register_init_var(void *, void *, long);"
277        "class %s__CONSTR__ {\n"
278        "  public: %s__CONSTR__() {\n"
279        "    pSingular_register_init_var(&%s, &%s__INIT__, sizeof(%s));\n"
280        "  }\n"
281        "} %s__AUX__;\n"
282      )->replace_all(S("%s"), var_name)));
283    }
284  }
285}
286
287void EmitEpilogue(Parser *parser) {
288  if (init_list->len() == 0 && class_vars->count() == 0)
289    return;
290  Str *modulename = parser->source->modulename;
291  TokenList *output = parser->output;
292  for (Int i = 0; i < output->len(); i++) {
293    Token &token = output->at(i);
294    if (token.sym == SymIdent && class_vars->contains(token.str)) {
295      Int j = i-1;
296      while (j >= 0 && TEST(SymsWS | BIT(SymAst), output->at(j).sym))
297        j--;
298      if (j < 0 || !type_prefix_set->contains(output->at(j).str))
299        token.str = class_vars->at(token.str);
300    }
301  }
302  if (init_list->len() == 0)
303    return;
304  Str *init_part;
305  if (parser->c_source()) {
306    init_part = S("\n"
307      "void pSingular_init_var(const void *s, const void *t, long n);\n"
308      "void *pSingular_alloc_var(long n);\n"
309      "void pSingular_register_init(void (*f)());\n"
310      "static void pSingular_mod_init() {\n"
311      );
312
313  } else {
314    init_part = S("\n"
315      "extern \"C\" {\n"
316      "void pSingular_init_var(const void *s, const void *t, long n);\n"
317      "void *pSingular_alloc_var(long n);\n"
318      "void pSingular_register_init(void (*f)());\n"
319      "}\n"
320      "typedef struct {\n"
321      "  void *target; void *source; long size;\n"
322      "} pSingular_var_desc;\n"
323      "static pSingular_var_desc pSingular_var_descs[%n];\n"
324      "static void pSingular_register_init_var(void *t, void *s, long n) {\n"
325      "  pSingular_var_desc * p = pSingular_var_descs;\n"
326      "  while (p->target) p++;\n"
327      "  p->target = t; p->source = s; p->size = n;\n"
328      "}\n"
329      "static void pSingular_mod_init() {\n"
330      );
331  }
332  for (Int i = 0; i < init_list->len(); i++) {
333    Str *var_name = init_list->at(i);
334    if (class_vars->contains(var_name)) {
335      Str *type = class_types->at(var_name);
336      if (namespaced->contains(var_name)) {
337        type = namespaced->at(var_name)->clone()->add("::")->add(type);
338        var_name = namespaced->at(var_name)->clone()->add("::")->add(var_name);
339      }
340      init_part->add(S(
341        "  %s = (%c *)pSingular_alloc_var((long)sizeof(%c));\n"
342        "  pSingular_init_var(%s, &%s__INIT__, (long) sizeof(%s));\n"
343      )->replace_all(S("%c"), type)->replace_all(S("%s"), var_name));
344    } else {
345      init_part->add(
346        S("  pSingular_init_var((void *)&%s, (void *)&%s__INIT__, (long) sizeof(%s));\n")
347        ->replace_all(S("%s"), var_name)
348      );
349    }
350  }
351  init_part->add("}\n");
352  init_part = init_part->replace_all(S("%n"), S(parser->init_count+1));
353  parser->emit(Token(SymGen, init_part));
354  Str *init_rest;
355  if (parser->c_source()) {
356    init_rest = S(
357      "__attribute__((constructor))"
358      "static void pSingular_init_%s(void) {\n"
359      "  pSingular_register_init(pSingular_mod_init);\n"
360      "}\n"
361    );
362  } else {
363    init_rest = S(
364      "static struct pSingular_Init_%s {\n"
365      "  pSingular_Init_%s() {\n"
366      "    pSingular_register_init(pSingular_mod_init);\n"
367      "  }\n"
368      "} pSingular_init_%s;\n"
369    );
370  }
371  init_rest = init_rest->replace_all(S("%s"), modulename);
372  parser->emit(Token(SymGen, init_rest));
373}
374
375void TransformVarDecl(Parser *parser, Str *storage_class,
376    bool is_class, bool is_toplevel, DeclType decl_type) {
377  // We rewrite: VAR type a, b = init, c;
378  // as:
379  // storage_class type a;
380  // storage_class type b;
381  // static type b__INIT__;
382  // storage_class type c;
383  // Init(b, init);
384  State saved = parser->save();
385  Int special_pos = parser->current_pos();
386  parser->current().str = storage_class; // rewrite contents
387  parser->advance(); // skip past special token
388  parser->skip_while(SymsWS);
389  Int type_start = parser->current_pos();
390  parser->advance();
391  parser->skip_while(SymIdent | SymColonColon | SymsWS);
392  Int type_end = parser->current_pos();
393  for(;;) {
394    Int var_pos = -1, var_start = -1, var_end = -1;
395    var_start = parser->current_pos();
396    parser->skip_while(SymsTypePrefix | BIT(SymWS) | BIT(SymClass));
397    if (TEST(SymsEndDecl | BIT(SymLBrkt), parser->current_sym())) {
398      // We are one symbol past the initial variable identifier.
399      var_pos = parser->find_back_until(BIT(SymIdent));
400      var_end = var_pos + 1;
401    } else {
402      // We have a function pointer declaration
403      State tmp = parser->save();
404      var_start = parser->current_pos();
405      parser->skip_until(BIT(SymIdent));
406      if (parser->current_sym() == SymIdent)
407        var_pos = parser->current_pos();
408      parser->restore(tmp);
409      parser->safe_skip_until(SymsEndDecl);
410      var_end = parser->current_pos();
411    }
412    Int init_start = -1, init_end = -1;
413    if (parser->current_sym() == SymEqual) {
414      init_start = parser->current_pos();
415      parser->advance();
416      parser->safe_skip_until(BIT(SymComma) | BIT(SymSemicolon));
417      init_end = parser->current_pos();
418    }
419    switch (parser->current_sym()) {
420      case SymComma:
421        EmitDecl(parser, storage_class,
422          type_start, type_end, var_start, var_end,
423          init_start, init_end, var_pos, is_class, is_toplevel, decl_type);
424        parser->advance();
425        break;
426      case SymSemicolon:
427        EmitDecl(parser, storage_class,
428          type_start, type_end, var_start, var_end,
429          init_start, init_end, var_pos, is_class, is_toplevel, decl_type);
430        parser->advance();
431        parser->mark();
432        return;
433      case SymEOF:
434        return; // error
435      default:
436        assert(0, "exhaustive switch hits default case");
437        return;
438    }
439  }
440}
441
442bool IsToplevel(Arr<int> *stack) {
443  if (stack->len() == 0) return true;
444  for (Int i = 0; i < stack->len(); i++) {
445    if (!stack->at(i)) return false;
446  }
447  return true;
448}
449
450TokenList *Transform(SourceFile *source) {
451  Parser *parser = new Parser(source);
452  Arr<int> *toplevel = new Arr<int>();
453  int tl = 0;
454  while (parser->current().sym != SymEOF) {
455    parser->skip_until(SymsSpecial);
456    parser->push_marked();
457    bool is_toplevel = IsToplevel(toplevel);
458    switch (parser->current().sym) {
459      case SymVAR:
460        TransformVarDecl(parser, decl_var,
461          false, is_toplevel, NormalDecl);
462        break;
463      case SymEXTERN_VAR:
464        parser->current().str = decl_extern_var;
465        parser->advance();
466        parser->push_marked();
467        break;
468      case SymSTATIC_VAR:
469        TransformVarDecl(parser, decl_static_var,
470          false, is_toplevel, StaticDecl);
471        break;
472      case SymINST_VAR:
473        TransformVarDecl(parser, decl_var,
474          true, is_toplevel, NormalDecl);
475        break;
476      case SymEXTERN_INST_VAR:
477        TransformVarDecl(parser, decl_extern_var,
478          true, is_toplevel, ExternDecl);
479        break;
480      case SymSTATIC_INST_VAR:
481        TransformVarDecl(parser, decl_static_var,
482          true, is_toplevel, StaticDecl);
483        break;
484      case SymExtern:
485        parser->advance();
486        if (parser->current().sym != SymLiteral)
487          break;
488        if (!parser->current().str->eq("\"C\""))
489          break;
490        tl = 1;
491        break;
492      case SymNamespace:
493        tl = 1;
494        parser->advance();
495        break;
496      case SymLBrace:
497        toplevel->add(tl);
498        parser->advance();
499        break;
500      case SymRBrace:
501        if (toplevel->len() > 0)
502          toplevel->pop();
503        tl = 0;
504        parser->advance();
505        break;
506      case SymEOF:
507        break;
508      default:
509        assert(0, "exhaustive switch hits default case");
510        return NULL;
511    }
512  }
513  EmitEpilogue(parser);
514  return parser->output;
515}
516
517Str *TestPreProcessor(Str *filename) {
518  SourceFile *source = ReadSource(filename);
519  if (!source) {
520    return S("ERROR: File not found: ")->add(filename)->add("\n");
521  }
522  TokenList *tokens = Transform(source);
523  Str *result = new Str();
524  for (Int i = 0; i < tokens->len(); i++) {
525    result->add(tokens->at(i).str);
526  }
527  return result;
528}
529
530Str *RunPreProcessor(Str *filename, Str *filedata) {
531  SourceFile *source = ReadSource(filename, filedata);
532  TokenList *tokens = Transform(source);
533  Str *result = new Str();  for (Int i = 0; i < tokens->len(); i++) {
534    result->add(tokens->at(i).str);
535  }
536  return result;
537}
Note: See TracBrowser for help on using the repository browser.