source: git/ppcc/src/parser.cc @ 54b24c

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