source: rtems-central/formal/promela/src/src/modules/promela_yacc/promela/yacc.py @ 5d08ea3

Last change on this file since 5d08ea3 was 5d08ea3, checked in by Andrew Butterfield <Andrew.Butterfield@…>, on 01/13/23 at 15:37:36

forked from https://github.com/johnyf/promela,
commit 32d14184a50e920a92201058e4f601329be8c9c7

  • Property mode set to 100644
File size: 24.3 KB
Line 
1"""Parser for Promela, using Python Lex-Yacc (PLY).
2
3
4References
5==========
6
7Holzmann G.J., The SPIN Model Checker,
8    Addison-Wesley, 2004, pp. 365--368
9    http://spinroot.com/spin/Man/Quick.html
10"""
11from __future__ import absolute_import
12from __future__ import division
13import logging
14import os
15import subprocess
16import warnings
17import ply.yacc
18# inline
19#
20# import promela.ast as promela_ast
21# from promela import lex
22
23
24TABMODULE = 'promela.promela_parsetab'
25logger = logging.getLogger(__name__)
26
27
28class Parser(object):
29    """Production rules for Promela parser."""
30
31    logger = logger
32    tabmodule = TABMODULE
33    start = 'program'
34    # http://spinroot.com/spin/Man/operators.html
35    # spin.y
36    # lowest to highest
37    precedence = (
38        ('right', 'EQUALS'),
39        ('left', 'TX2', 'RCV', 'R_RCV'),
40        ('left', 'IMPLIES', 'EQUIV'),
41        ('left', 'LOR'),
42        ('left', 'LAND'),
43        ('left', 'ALWAYS', 'EVENTUALLY'),
44        ('left', 'UNTIL', 'WEAK_UNTIL', 'RELEASE'),
45        ('right', 'NEXT'),
46        ('left', 'OR'),
47        ('left', 'XOR'),
48        ('left', 'AND'),
49        ('left', 'EQ', 'NE'),
50        ('left', 'LT', 'LE', 'GT', 'GE'),
51        ('left', 'LSHIFT', 'RSHIFT'),
52        ('left', 'PLUS', 'MINUS'),
53        ('left', 'TIMES', 'DIVIDE', 'MOD'),
54        ('left', 'INCR', 'DECR'),
55        ('right', 'LNOT', 'NOT', 'UMINUS', 'NEG'),  # LNOT is also SND
56        ('left', 'DOT'),
57        ('left', 'LPAREN', 'RPAREN', 'LBRACKET', 'RBRACKET'))
58
59    def __init__(self, ast=None, lexer=None):
60        if ast is None:
61            import promela.ast as ast
62        if lexer is None:
63            from promela import lex
64            lexer = lex.Lexer()
65        self.lexer = lexer
66        self.ast = ast
67        self.tokens = self.lexer.tokens
68        self.build()
69
70    def build(self, tabmodule=None, outputdir='', write_tables=False,
71              debug=False, debuglog=None, errorlog=None):
72        """Build parser using `ply.yacc`.
73
74        Default table module is `self.tabmodule`.
75        Module logger used as default debug logger.
76        Default error logger is that created by PLY.
77        """
78        if tabmodule is None:
79            tabmodule = self.tabmodule
80        if debug and debuglog is None:
81            debuglog = self.logger
82        self.parser = ply.yacc.yacc(
83            method='LALR',
84            module=self,
85            start=self.start,
86            tabmodule=tabmodule,
87            outputdir=outputdir,
88            write_tables=write_tables,
89            debug=debug,
90            debuglog=debuglog,
91            errorlog=errorlog)
92
93    def parse(self, promela):
94        """Parse string of Promela code."""
95        s = cpp(promela)
96        program = self.parser.parse(
97            s, lexer=self.lexer.lexer, debug=self.logger)
98        return program
99
100    def _iter(self, p):
101        if p[2] is not None:
102            p[1].append(p[2])
103        return p[1]
104
105    def _end(self, p):
106        if p[1] is None:
107            return list()
108        else:
109            return [p[1]]
110
111    # Top-level constructs
112    # ====================
113
114    def p_program(self, p):
115        """program : units"""
116        p[0] = self.ast.Program(p[1])
117
118    def p_units_iter(self, p):
119        """units : units unit"""
120        p[0] = self._iter(p)
121
122    def p_units_end(self, p):
123        """units : unit"""
124        p[0] = self._end(p)
125
126    # TODO: events, c_fcts, ns, error
127    def p_unit_proc(self, p):
128        """unit : proc
129                | init
130                | claim
131                | ltl
132        """
133        p[0] = p[1]
134
135    def p_unit_decl(self, p):
136        """unit : one_decl
137                | utype
138        """
139        p[0] = p[1]
140
141    def p_unit_semi(self, p):
142        """unit : semi"""
143
144    def p_proc(self, p):
145        ("""proc : prefix_proctype NAME"""
146         """       LPAREN decl RPAREN"""
147         """       opt_priority opt_enabler"""
148         """       body
149         """)
150        inst = p[1]
151        name = p[2]
152        args = p[4]
153        priority = p[6]
154        enabler = p[7]
155        body = p[8]
156
157        p[0] = self.ast.Proctype(
158            name, body, args=args, priority=priority,
159            provided=enabler, **inst)
160
161    # instantiator
162    def p_inst(self, p):
163        """prefix_proctype : ACTIVE opt_index proctype"""
164        d = p[3]
165        if p[2] is None:
166            n_active = self.ast.Integer('1')
167        else:
168            n_active = p[2]
169        d['active'] = n_active
170        p[0] = d
171
172    def p_inactive_proctype(self, p):
173        """prefix_proctype : proctype"""
174        p[0] = p[1]
175
176    def p_opt_index(self, p):
177        """opt_index : LBRACKET expr RBRACKET
178                     | LBRACKET NAME RBRACKET
179        """
180        p[0] = p[2]
181
182    def p_opt_index_empty(self, p):
183        """opt_index : empty"""
184
185    def p_init(self, p):
186        """init : INIT opt_priority body"""
187        p[0] = self.ast.Init(name='init', body=p[3], priority=p[2])
188
189    def p_claim(self, p):
190        """claim : CLAIM optname body"""
191        name = p[2] if p[2] else 'never'
192        p[0] = self.ast.NeverClaim(name=name, body=p[3])
193
194    # user-defined type
195    def p_utype(self, p):
196        """utype : TYPEDEF NAME LBRACE decl_lst RBRACE"""
197        seq = self.ast.Sequence(p[4])
198        p[0] = self.ast.TypeDef(p[2], seq)
199
200    def p_ltl(self, p):
201        """ltl : LTL LBRACE expr RBRACE"""
202        p[0] = self.ast.LTL(p[3])
203
204    # Declarations
205    # ============
206
207    def p_decl(self, p):
208        """decl : decl_lst"""
209        p[0] = self.ast.Sequence(p[1])
210
211    def p_decl_empty(self, p):
212        """decl : empty"""
213
214    def p_decl_lst_iter(self, p):
215        """decl_lst : one_decl SEMI decl_lst"""
216        p[0] = [p[1]] + p[3]
217
218    def p_decl_lst_end(self, p):
219        """decl_lst : one_decl"""
220        p[0] = [p[1]]
221
222    def p_one_decl_visible(self, p):
223        """one_decl : vis typename var_list
224                    | vis NAME var_list
225        """
226        visible = p[1]
227        typ = p[2]
228        var_list = p[3]
229
230        p[0] = self.one_decl(typ, var_list, visible)
231
232    def p_one_decl(self, p):
233        """one_decl : typename var_list
234                    | NAME var_list
235        """
236        typ = p[1]
237        var_list = p[2]
238        p[0] = self.one_decl(typ, var_list)
239
240    def one_decl(self, typ, var_list, visible=None):
241        c = list()
242        for d in var_list:
243            v = self.ast.VarDef(vartype=typ, visible=visible, **d)
244            c.append(v)
245        return self.ast.Sequence(c)
246
247    # message type declaration
248    def p_one_decl_mtype_vis(self, p):
249        """one_decl : vis MTYPE asgn LBRACE name_list RBRACE"""
250        p[0] = self.ast.MessageType(p[5], visible=p[1])
251
252    def p_one_decl_mtype(self, p):
253        """one_decl : MTYPE asgn LBRACE name_list RBRACE"""
254        p[0] = self.ast.MessageType(p[3])
255
256    def p_name_list_iter(self, p):
257        """name_list : name_list COMMA NAME"""
258        p[1].append(p[3])
259        p[0] = p[1]
260
261    def p_name_list_end(self, p):
262        """name_list : NAME"""
263        p[0] = [p[1]]
264
265    def p_var_list_iter(self, p):
266        """var_list : ivar COMMA var_list"""
267        p[0] = [p[1]] + p[3]
268
269    def p_var_list_end(self, p):
270        """var_list : ivar"""
271        p[0] = [p[1]]
272
273    # TODO: vardcl asgn LBRACE c_list RBRACE
274
275    # ivar = initialized variable
276    def p_ivar(self, p):
277        """ivar : vardcl"""
278        p[0] = p[1]
279
280    def p_ivar_asgn(self, p):
281        """ivar : vardcl asgn expr"""
282        expr = self.ast.Expression(p[3])
283        p[1]['initval'] = expr
284        p[0] = p[1]
285
286    def p_vardcl(self, p):
287        """vardcl : NAME"""
288        p[0] = {'name': p[1]}
289
290    # p.403, SPIN manual
291    def p_vardcl_unsigned(self, p):
292        """vardcl : NAME COLON const"""
293        p[0] = {'name': p[1], 'bitwidth': p[3]}
294
295    def p_vardcl_array(self, p):
296        """vardcl : NAME LBRACKET const_expr RBRACKET"""
297        p[0] = {'name': p[1], 'length': p[3]}
298
299    def p_vardcl_chan(self, p):
300        """vardcl : vardcl EQUALS ch_init"""
301        p[1].update(p[3])
302        p[0] = p[1]
303
304    def p_typename(self, p):
305        """typename : BIT
306                    | BOOL
307                    | BYTE
308                    | CHAN
309                    | INT
310                    | PID
311                    | SHORT
312                    | UNSIGNED
313                    | MTYPE
314        """
315        p[0] = p[1]
316
317    def p_ch_init(self, p):
318        ("""ch_init : LBRACKET const_expr RBRACKET """
319         """ OF LBRACE typ_list RBRACE""")
320        p[0] = {'length': p[2], 'msg_types': p[6]}
321
322    def p_typ_list_iter(self, p):
323        """typ_list : typ_list COMMA basetype"""
324        p[1].append(p[3])
325        p[0] = p[1]
326
327    def p_typ_list_end(self, p):
328        """typ_list : basetype"""
329        p[0] = [p[1]]
330
331    # TODO: | UNAME | error
332    def p_basetype(self, p):
333        """basetype : typename"""
334        p[0] = p[1]
335
336    # References
337    # ==========
338
339    def p_varref(self, p):
340        """varref : cmpnd"""
341        p[0] = p[1]
342
343    def p_cmpnd_iter(self, p):
344        """cmpnd : cmpnd PERIOD cmpnd %prec DOT"""
345        p[0] = self.ast.VarRef(extension=p[3], **p[1])
346
347    def p_cmpnd_end(self, p):
348        """cmpnd : pfld"""
349        p[0] = self.ast.VarRef(**p[1])
350
351    # pfld = prefix field
352    def p_pfld_indexed(self, p):
353        """pfld : NAME LBRACKET expr RBRACKET"""
354        p[0] = {'name': p[1], 'index': p[3]}
355
356    def p_pfld(self, p):
357        """pfld : NAME"""
358        p[0] = {'name': p[1]}
359
360    # Attributes
361    # ==========
362
363    def p_opt_priority(self, p):
364        """opt_priority : PRIORITY number"""
365        p[0] = p[2]
366
367    def p_opt_priority_empty(self, p):
368        """opt_priority : empty"""
369
370    def p_opt_enabler(self, p):
371        """opt_enabler : PROVIDED LPAREN expr RPAREN"""
372        p[0] = p[3]
373
374    def p_opt_enabler_empty(self, p):
375        """opt_enabler : empty"""
376
377    def p_body(self, p):
378        """body : LBRACE sequence os RBRACE"""
379        p[0] = p[2]
380
381    # Sequence
382    # ========
383
384    def p_sequence(self, p):
385        """sequence : sequence msemi step"""
386        p[1].append(p[3])
387        p[0] = p[1]
388
389    def p_sequence_ending_with_atomic(self, p):
390        """sequence : seq_block step"""
391        p[1].append(p[2])
392        p[0] = p[1]
393
394    def p_sequence_single(self, p):
395        """sequence : step"""
396        p[0] = self.ast.Sequence([p[1]])
397
398    def p_seq_block(self, p):
399        """seq_block : sequence msemi atomic
400                     | sequence msemi dstep
401        """
402        p[1].append(p[3])
403        p[0] = p[1]
404
405    def p_seq_block_iter(self, p):
406        """seq_block : seq_block atomic
407                     | seq_block dstep
408        """
409        p[1].append(p[2])
410        p[0] = p[1]
411
412    def p_seq_block_single(self, p):
413        """seq_block : atomic
414                     | dstep
415        """
416        p[0] = [p[1]]
417
418    # TODO: XU vref_lst
419    def p_step_1(self, p):
420        """step : one_decl
421                | stmnt
422        """
423        p[0] = p[1]
424
425    def p_step_labeled(self, p):
426        """step : NAME COLON one_decl"""
427        raise Exception(
428            'label preceding declaration: {s}'.format(s=p[3]))
429
430    def p_step_3(self, p):
431        """step : NAME COLON XR
432                | NAME COLON XS
433        """
434        raise Exception(
435            'label preceding xr/xs claim')
436
437    def p_step_4(self, p):
438        """step : stmnt UNLESS stmnt"""
439        p[0] = (p[1], 'unless', p[3])
440        self.logger.warning('UNLESS not interpreted yet')
441
442    # Statement
443    # =========
444
445    def p_stmnt(self, p):
446        """stmnt : special
447                 | statement
448        """
449        p[0] = p[1]
450
451    # Stmnt in spin.y
452    def p_statement_asgn(self, p):
453        """statement : varref asgn full_expr"""
454        p[0] = self.ast.Assignment(var=p[1], value=p[3])
455
456    def p_statement_incr(self, p):
457        """statement : varref INCR"""
458        one = self.ast.Integer('1')
459        expr = self.ast.Expression(self.ast.Binary('+', p[1], one))
460        p[0] = self.ast.Assignment(p[1], expr)
461
462    def p_statement_decr(self, p):
463        """statement : varref DECR"""
464        one = self.ast.Integer('1')
465        expr = self.ast.Expression(self.ast.Binary('-', p[1], one))
466        p[0] = self.ast.Assignment(p[1], expr)
467
468    def p_statement_assert(self, p):
469        """statement : ASSERT full_expr"""
470        p[0] = self.ast.Assert(p[2])
471
472    def p_statement_fifo_receive(self, p):
473        """statement : varref RCV rargs"""
474        p[0] = self.ast.Receive(p[1], p[3])
475
476    def p_statement_copy_fifo_receive(self, p):
477        """statement : varref RCV LT rargs GT"""
478        p[0] = self.ast.Receive(p[1], p[4])
479
480    def p_statement_random_receive(self, p):
481        """statement : varref R_RCV rargs"""
482        p[0] = self.ast.Receive(p[1], p[3])
483
484    def p_statement_copy_random_receive(self, p):
485        """statement : varref R_RCV LT rargs GT"""
486        p[0] = self.ast.Receive(p[1], p[4])
487
488    def p_statement_tx2(self, p):
489        """statement : varref TX2 margs"""
490        p[0] = self.ast.Send(p[1], p[3])
491
492    def p_statement_full_expr(self, p):
493        """statement : full_expr"""
494        p[0] = p[1]
495
496    def p_statement_else(self, p):
497        """statement : ELSE"""
498        p[0] = self.ast.Else()
499
500    def p_statement_atomic(self, p):
501        """statement : atomic"""
502        p[0] = p[1]
503
504    def p_atomic(self, p):
505        """atomic : ATOMIC LBRACE sequence os RBRACE"""
506        s = p[3]
507        s.context = 'atomic'
508        p[0] = s
509
510    def p_statement_dstep(self, p):
511        """statement : dstep"""
512        p[0] = p[1]
513
514    def p_dstep(self, p):
515        """dstep : D_STEP LBRACE sequence os RBRACE"""
516        s = p[3]
517        s.context = 'd_step'
518        p[0] = s
519
520    def p_statement_braces(self, p):
521        """statement : LBRACE sequence os RBRACE"""
522        p[0] = p[2]
523
524    # the stmt of line 696 in spin.y collects the inline ?
525    def p_statement_call(self, p):
526        """statement : NAME LPAREN args RPAREN"""
527        # NAME = INAME = inline
528        c = self.ast.Inline(p[1], p[3])
529        p[0] = self.ast.Sequence([c])
530
531    def p_statement_assgn_call(self, p):
532        """statement : varref asgn NAME LPAREN args RPAREN statement"""
533        inline = self.ast.Inline(p[3], p[5])
534        p[0] = self.ast.Assignment(p[1], inline)
535
536    def p_statement_return(self, p):
537        """statement : RETURN full_expr"""
538        p[0] = self.ast.Return(p[2])
539
540    def p_printf(self, p):
541        """statement : PRINT LPAREN STRING prargs RPAREN"""
542        p[0] = self.ast.Printf(p[3], p[4])
543
544    # yet unimplemented for statement:
545        # SET_P l_par two_args r_par
546        # PRINTM l_par varref r_par
547        # PRINTM l_par CONST r_par
548        # ccode
549
550    # Special
551    # =======
552
553    def p_special(self, p):
554        """special : varref RCV"""
555        p[0] = self.ast.Receive(p[1])
556
557    def p_varref_lnot(self, p):
558        """special : varref LNOT margs"""
559        raise NotImplementedError
560
561    def p_break(self, p):
562        """special : BREAK"""
563        p[0] = self.ast.Break()
564
565    def p_goto(self, p):
566        """special : GOTO NAME"""
567        p[0] = self.ast.Goto(p[2])
568
569    def p_labeled_stmt(self, p):
570        """special : NAME COLON stmnt"""
571        p[0] = self.ast.Label(p[1], p[3])
572
573    def p_labeled(self, p):
574        """special : NAME COLON"""
575        p[0] = self.ast.Label(
576            p[1],
577            self.ast.Expression(self.ast.Bool('true')))
578
579    def p_special_if(self, p):
580        """special : IF options FI"""
581        p[0] = self.ast.Options('if', p[2])
582
583    def p_special_do(self, p):
584        """special : DO options OD"""
585        p[0] = self.ast.Options('do', p[2])
586
587    def p_options_end(self, p):
588        """options : option"""
589        p[0] = [p[1]]
590
591    def p_options_iter(self, p):
592        """options : options option"""
593        p[1].append(p[2])
594        p[0] = p[1]
595
596    def p_option(self, p):
597        """option : COLONS sequence os"""
598        s = p[2]
599        s.is_option = True
600        p[0] = s
601
602    # Expressions
603    # ===========
604
605    def p_full_expr(self, p):
606        """full_expr : expr
607                     | pexpr
608        """
609        p[0] = self.ast.Expression(p[1])
610
611    # probe expr = no negation allowed (positive)
612    def p_pexpr(self, p):
613        """pexpr : probe
614                 | LPAREN pexpr RPAREN
615                 | pexpr LAND pexpr
616                 | pexpr LAND expr
617                 | expr LAND pexpr
618                 | pexpr LOR pexpr
619                 | pexpr LOR expr
620                 | expr LOR pexpr
621        """
622        p[0] = 'pexpr'
623
624    def p_probe(self, p):
625        """probe : FULL LPAREN varref RPAREN
626                 | NFULL LPAREN varref RPAREN
627                 | EMPTY LPAREN varref RPAREN
628                 | NEMPTY LPAREN varref RPAREN
629        """
630        p[0] = 'probe'
631
632    def p_expr_paren(self, p):
633        """expr : LPAREN expr RPAREN"""
634        p[0] = p[2]
635
636    def p_expr_arithmetic(self, p):
637        """expr : expr PLUS expr
638                | expr MINUS expr
639                | expr TIMES expr
640                | expr DIVIDE expr
641                | expr MOD expr
642        """
643        p[0] = self.ast.Binary(p[2], p[1], p[3])
644
645    def p_expr_not(self, p):
646        """expr : NOT expr
647                | MINUS expr %prec UMINUS
648                | LNOT expr %prec NEG
649        """
650        p[0] = self.ast.Unary(p[1], p[2])
651
652    def p_expr_logical(self, p):
653        """expr : expr AND expr
654                | expr OR expr
655                | expr XOR expr
656                | expr LAND expr
657                | expr LOR expr
658        """
659        p[0] = self.ast.Binary(p[2], p[1], p[3])
660
661    # TODO: cexpr
662
663    def p_expr_shift(self, p):
664        """expr : expr LSHIFT expr
665                | expr RSHIFT expr
666        """
667        p[0] = p[1]
668
669    def p_expr_const_varref(self, p):
670        """expr : const
671                | varref
672        """
673        p[0] = p[1]
674
675    def p_expr_varref(self, p):
676        """expr : varref RCV LBRACKET rargs RBRACKET
677                | varref R_RCV LBRACKET rargs RBRACKET
678        """
679        p[0] = p[1]
680        warnings.warn('not implemented')
681
682    def p_expr_other(self, p):
683        """expr : LPAREN expr ARROW expr COLON expr RPAREN
684                | LEN LPAREN varref RPAREN
685                | ENABLED LPAREN expr RPAREN
686                | GET_P LPAREN expr RPAREN
687        """
688        p[0] = p[1]
689        warnings.warn('"{s}" not implemented'.format(s=p[1]))
690
691    def p_expr_run(self, p):
692        """expr : RUN aname LPAREN args RPAREN opt_priority"""
693        p[0] = self.ast.Run(p[2], p[4], p[6])
694
695    def p_expr_other_2(self, p):
696        """expr : TIMEOUT
697                | NONPROGRESS
698                | PC_VAL LPAREN expr RPAREN
699        """
700        raise NotImplementedError()
701
702    def p_expr_remote_ref_proctype_pc(self, p):
703        """expr : NAME AT NAME
704        """
705        p[0] = self.ast.RemoteRef(p[1], p[3])
706
707    def p_expr_remote_ref_pid_pc(self, p):
708        """expr : NAME LBRACKET expr RBRACKET AT NAME"""
709        p[0] = self.ast.RemoteRef(p[1], p[6], pid=p[3])
710
711    def p_expr_remote_ref_var(self, p):
712        """expr : NAME LBRACKET expr RBRACKET COLON pfld"""
713        # | NAME COLON pfld %prec DOT2
714        raise NotImplementedError()
715
716    def p_expr_comparator(self, p):
717        """expr : expr EQ expr
718                | expr NE expr
719                | expr LT expr
720                | expr LE expr
721                | expr GT expr
722                | expr GE expr
723        """
724        p[0] = self.ast.Binary(p[2], p[1], p[3])
725
726    def p_binary_ltl_expr(self, p):
727        """expr : expr UNTIL expr
728                | expr WEAK_UNTIL expr
729                | expr RELEASE expr
730                | expr IMPLIES expr
731                | expr EQUIV expr
732        """
733        p[0] = self.ast.Binary(p[2], p[1], p[3])
734
735    def p_unary_ltl_expr(self, p):
736        """expr : NEXT expr
737                | ALWAYS expr
738                | EVENTUALLY expr
739        """
740        p[0] = self.ast.Unary(p[1], p[2])
741
742    # Constants
743    # =========
744
745    def p_const_expr_const(self, p):
746        """const_expr : const"""
747        p[0] = p[1]
748
749    def p_const_expr_unary(self, p):
750        """const_expr : MINUS const_expr %prec UMINUS"""
751        p[0] = self.ast.Unary(p[1], p[2])
752
753    def p_const_expr_binary(self, p):
754        """const_expr : const_expr PLUS const_expr
755                      | const_expr MINUS const_expr
756                      | const_expr TIMES const_expr
757                      | const_expr DIVIDE const_expr
758                      | const_expr MOD const_expr
759        """
760        p[0] = self.ast.Binary(p[2], p[1], p[3])
761
762    def p_const_expr_paren(self, p):
763        """const_expr : LPAREN const_expr RPAREN"""
764        p[0] = p[2]
765
766    def p_const(self, p):
767        """const : boolean
768                 | number
769        """
770        # lex maps `skip` to `TRUE`
771        p[0] = p[1]
772
773    def p_bool(self, p):
774        """boolean : TRUE
775                   | FALSE
776        """
777        p[0] = self.ast.Bool(p[1])
778
779    def p_number(self, p):
780        """number : INTEGER"""
781        p[0] = self.ast.Integer(p[1])
782
783    # Auxiliary
784    # =========
785
786    def p_two_args(self, p):
787        """two_args : expr COMMA expr"""
788
789    def p_args(self, p):
790        """args : arg"""
791        p[0] = p[1]
792
793    def p_prargs(self, p):
794        """prargs : COMMA arg"""
795        p[0] = p[2]
796
797    def p_prargs_empty(self, p):
798        """prargs : empty"""
799
800    def p_args_empty(self, p):
801        """args : empty"""
802
803    def p_margs(self, p):
804        """margs : arg
805                 | expr LPAREN arg RPAREN
806        """
807
808    def p_arg(self, p):
809        """arg : expr
810               | expr COMMA arg
811        """
812        p[0] = 'arg'
813
814    # TODO: CONST, MINUS CONST %prec UMIN
815    def p_rarg(self, p):
816        """rarg : varref
817                | EVAL LPAREN expr RPAREN
818        """
819        p[0] = 'rarg'
820
821    def p_rargs(self, p):
822        """rargs : rarg
823                 | rarg COMMA rargs
824                 | rarg LPAREN rargs RPAREN
825                 | LPAREN rargs RPAREN
826        """
827
828    def p_proctype(self, p):
829        """proctype : PROCTYPE
830                    | D_PROCTYPE
831        """
832        if p[1] == 'proctype':
833            p[0] = dict(d_proc=False)
834        else:
835            p[0] = dict(d_proc=True)
836
837    # PNAME
838    def p_aname(self, p):
839        """aname : NAME"""
840        p[0] = p[1]
841
842    # optional name
843    def p_optname(self, p):
844        """optname : NAME"""
845        p[0] = p[1]
846
847    def p_optname_empty(self, p):
848        """optname : empty"""
849
850    # optional semi
851    def p_os(self, p):
852        """os : empty
853              | semi
854        """
855        p[0] = ';'
856
857    # multi-semi
858    def p_msemi(self, p):
859        """msemi : semi
860                 | msemi semi
861        """
862        p[0] = ';'
863
864    def p_semi(self, p):
865        """semi : SEMI
866                | ARROW
867        """
868        p[0] = ';'
869
870    def p_asgn(self, p):
871        """asgn : EQUALS
872                | empty
873        """
874        p[0] = None
875
876    def p_visible(self, p):
877        """vis : HIDDEN
878               | SHOW
879               | ISLOCAL
880        """
881        p[0] = {'visible': p[1]}
882
883    def p_empty(self, p):
884        """empty : """
885
886    def p_error(self, p):
887        raise Exception('syntax error at: {p}'.format(p=p))
888
889
890def cpp(s):
891    """Call the C{C} preprocessor with input C{s}."""
892    try:
893        p = subprocess.Popen(['cpp', '-E', '-x', 'c'],
894                             stdin=subprocess.PIPE,
895                             stdout=subprocess.PIPE,
896                             stderr=subprocess.PIPE,
897                             universal_newlines=True)
898    except OSError as e:
899        if e.errno == os.errno.ENOENT:
900            raise Exception('C preprocessor (cpp) not found in path.')
901        else:
902            raise
903    logger.debug('cpp input:\n' + s)
904    stdout, stderr = p.communicate(s)
905    logger.debug('cpp returned: {c}'.format(c=p.returncode))
906    logger.debug('cpp stdout:\n {out}'.format(out=stdout))
907    return stdout
908
909
910def rebuild_table(parser, tabmodule):
911    # log details to file
912    h = logging.FileHandler('log.txt', mode='w')
913    debuglog = logging.getLogger()
914    debuglog.addHandler(h)
915    debuglog.setLevel('DEBUG')
916    import os
917    outputdir = './'
918    # rm table files to force rebuild to get debug output
919    tablepy = tabmodule + '.py'
920    tablepyc = tabmodule + '.pyc'
921    try:
922        os.remove(tablepy)
923    except:
924        print('no "{t}" found'.format(t=tablepy))
925    try:
926        os.remove(tablepyc)
927    except:
928        print('no "{t}" found'.format(t=tablepyc))
929    parser.build(tabmodule, outputdir=outputdir,
930                 write_tables=True, debug=True,
931                 debuglog=debuglog)
932
933
934if __name__ == '__main__':
935    rebuild_table(Parser(), TABMODULE.split('.')[-1])
936
937
938# TODO
939#
940# expr << expr
941# expr >> expr
942# (expr -> expr : expr)
943# run func(args) priority
944# len(varref)
945# enabled(expr)
946# get_p(expr)
947# var ? [rargs]
948# var ?? [rargs]
949# timeout
950# nonprogress
951# pc_val(expr)
952# name[expr] @ name
953# name[expr] : pfld
954# name @ name
955# name : pfld
Note: See TracBrowser for help on using the repository browser.