Prefix all build output file names of files which end up in the build
[coreboot.git] / util / sconfig / parsedesc.g
1 ######################################################################
2 # The remainder of this file is from parsedesc.{g,py}
3
4 def append(lst, x):
5     "Imperative append"
6     lst.append(x)
7     return lst
8
9 def add_inline_token(tokens, str):
10     tokens.insert( 0, (str, eval(str, {}, {})) )
11     return Terminal(str)
12
13 def cleanup_choice(lst):
14     if len(lst) == 0: return Sequence([])
15     if len(lst) == 1: return lst[0]
16     return apply(Choice, tuple(lst))
17
18 def cleanup_sequence(lst):
19     if len(lst) == 1: return lst[0]
20     return apply(Sequence, tuple(lst))
21
22 def cleanup_rep(node, rep):
23     if rep == 'star':   return Star(node)
24     elif rep == 'plus': return Plus(node)
25     else:               return node
26
27 def resolve_name(tokens, id, args):
28     if id in map(lambda x: x[0], tokens):
29         # It's a token
30         if args: 
31             print 'Warning: ignoring parameters on TOKEN %s<<%s>>' % (id, args)
32         return Terminal(id)
33     else:
34         # It's a name, so assume it's a nonterminal
35         return NonTerminal(id, args)
36
37 %%
38 parser ParserDescription:
39     option:      "context-insensitive-scanner"
40
41     ignore:      "[ \t\r\n]+"
42     ignore:      "#.*?\r?\n"
43     token END:   "$"
44     token ATTR:  "<<.+?>>"
45     token STMT:  "{{.+?}}"
46     token ID:    '[a-zA-Z_][a-zA-Z_0-9]*'
47     token STR:   '[rR]?\'([^\\n\'\\\\]|\\\\.)*\'|[rR]?"([^\\n"\\\\]|\\\\.)*"'
48     token LP:    '\\('
49     token RP:    '\\)'
50     token LB:    '\\['
51     token RB:    '\\]'
52     token OR:    '[|]'
53     token STAR:  '[*]'
54     token PLUS:  '[+]'
55     token QUEST: '[?]'
56     token COLON: ':'
57
58     rule Parser: "parser" ID ":"
59                    Options
60                    Tokens
61                    Rules<<Tokens>> 
62                  END 
63                  {{ return Generator(ID,Options,Tokens,Rules) }}
64
65     rule Options: {{ opt = {} }}
66                   ( "option" ":" Str {{ opt[Str] = 1 }} )*
67                   {{ return opt }}
68
69     rule Tokens:  {{ tok = [] }}
70                   (
71                     "token" ID ":" Str {{ tok.append( (ID,Str) ) }}
72                   | "ignore"   ":" Str {{ tok.append( ('#ignore',Str) ) }}
73                   )*
74                   {{ return tok }}
75
76     rule Rules<<tokens>>:
77                   {{ rul = [] }}
78                   (
79                     "rule" ID OptParam ":" ClauseA<<tokens>>
80                     {{ rul.append( (ID,OptParam,ClauseA) ) }}
81                   )*
82                   {{ return rul }}
83
84     rule ClauseA<<tokens>>:
85                   ClauseB<<tokens>>
86                   {{ v = [ClauseB] }}
87                   ( OR ClauseB<<tokens>> {{ v.append(ClauseB) }} )*
88                   {{ return cleanup_choice(v) }}
89
90     rule ClauseB<<tokens>>:
91                   {{ v = [] }}
92                   ( ClauseC<<tokens>> {{ v.append(ClauseC) }} )*
93                   {{ return cleanup_sequence(v) }}
94
95     rule ClauseC<<tokens>>:
96                   ClauseD<<tokens>>
97                   ( PLUS {{ return Plus(ClauseD) }}
98                   | STAR {{ return Star(ClauseD) }}
99                   |      {{ return ClauseD }} )
100
101     rule ClauseD<<tokens>>:
102                   STR {{ t = (STR, eval(STR,{},{})) }}
103                       {{ if t not in tokens: tokens.insert( 0, t ) }} 
104                       {{ return Terminal(STR) }}
105                 | ID OptParam {{ return resolve_name(tokens, ID, OptParam) }}
106                 | LP ClauseA<<tokens>> RP {{ return ClauseA }}
107                 | LB ClauseA<<tokens>> RB {{ return Option(ClauseA) }}
108                 | STMT {{ return Eval(STMT[2:-2]) }}
109
110     rule OptParam: [ ATTR {{ return ATTR[2:-2] }} ] {{ return '' }}
111     rule Str:   STR {{ return eval(STR,{},{}) }}
112 %%
113
114 # This replaces the default main routine
115
116 yapps_options = [
117     ('context-insensitive-scanner', 'context-insensitive-scanner',
118      'Scan all tokens (see docs)')
119     ]
120
121 def generate(inputfilename, outputfilename='', dump=0, **flags):
122     """Generate a grammar, given an input filename (X.g)
123     and an output filename (defaulting to X.py)."""
124
125     if not outputfilename:
126         if inputfilename[-2:]=='.g': outputfilename = inputfilename[:-2]+'.py'
127         else: raise "Invalid Filename", outputfilename
128         
129     print '    SCONFIG   ', join(outputfilename.split('/')[-5:], '/')
130     
131     DIVIDER = '\n%%\n' # This pattern separates the pre/post parsers
132     preparser, postparser = None, None # Code before and after the parser desc
133
134     # Read the entire file
135     s = open(inputfilename,'r').read()
136
137     # See if there's a separation between the pre-parser and parser
138     f = find(s, DIVIDER)
139     if f >= 0: preparser, s = s[:f]+'\n\n', s[f+len(DIVIDER):]
140
141     # See if there's a separation between the parser and post-parser
142     f = find(s, DIVIDER)
143     if f >= 0: s, postparser = s[:f], '\n\n'+s[f+len(DIVIDER):]
144
145     # Create the parser and scanner
146     p = ParserDescription(ParserDescriptionScanner(s))
147     if not p: return
148     
149     # Now parse the file
150     t = wrap_error_reporter(p, 'Parser')
151     if not t: return # Error
152     if preparser is not None: t.preparser = preparser
153     if postparser is not None: t.postparser = postparser
154
155     # Check the options
156     for f in t.options.keys():
157         for opt,_,_ in yapps_options:
158             if f == opt: break
159         else:
160             print 'Warning: unrecognized option', f
161     # Add command line options to the set
162     for f in flags.keys(): t.options[f] = flags[f]
163             
164     # Generate the output
165     if dump:
166         t.dump_information()
167     else:
168         t.output = open(outputfilename, 'w')
169         t.generate_output()
170
171 if __name__=='__main__':
172     import sys, getopt
173     optlist, args = getopt.getopt(sys.argv[1:], 'f:', ['dump'])
174     if not args or len(args) > 2:
175         print 'Usage:'
176         print '  python', sys.argv[0], '[flags] input.g [output.py]'
177         print 'Flags:'
178         print ('  --dump' + ' '*40)[:35] + 'Dump out grammar information'
179         for flag, _, doc in yapps_options:
180             print ('  -f' + flag + ' '*40)[:35] + doc
181     else:
182         # Read in the options and create a list of flags
183         flags = {}
184         for opt in optlist:
185             for flag, name, _ in yapps_options:
186                 if opt == ('-f', flag):
187                     flags[name] = 1
188                     break
189             else:
190                 if opt == ('--dump', ''):
191                     flags['dump'] = 1
192                 else:
193                     print 'Warning - unrecognized option:  ', opt[0], opt[1]
194
195         apply(generate, tuple(args), flags)