new config tool
[coreboot.git] / util / newconfig / config.g
1 import sys
2 import os
3 import re
4 import string
5
6 debug = 3
7
8 arch = ''
9 makebase = ''
10 ldscriptbase = ''
11 payloadfile = ''
12
13 makeoptions = {}
14 makeexpressions = []
15
16 # Key is the rule name. Value is a mkrule object.
17 makebaserules = {}
18
19 # List of targets in the order defined by makerule commands.
20 makerule_targets = {}
21
22 treetop = ''
23 target_dir = ''
24
25 sources = {}
26 objectrules = {}
27 # make these a hash so they will be unique.
28 driverrules = {}
29 ldscripts = []
30 userdefines = []
31 curpart = 0
32
33 globalvars = {}       # We will globals here
34 parts = {}
35
36 options = {}
37 # options in order defined. These will be unique due to use of hash 
38 # for options. 
39 options_by_order = []
40 crt0includes = []
41 partinstance = 0
42 curdir = '' 
43 dirstack = []
44 config_file_list = []
45
46 local_path = re.compile(r'^\.')
47
48 # -----------------------------------------------------------------------------
49 #                    Error Handling
50 # -----------------------------------------------------------------------------
51
52 class location:
53         class place:
54                 def __init__(self, file, line, command):
55                         self.file = file
56                         self.line = line
57                         self.command = command
58                 def next_line(self, command):
59                         self.line = self.line + 1
60                         self.command = command
61                 def at(self):
62                         return "%s:%d" % (self.file, self.line)
63         
64         def __init__ (self):
65                 self.stack = []
66
67         def file(self):
68                 return self.stack[-1].file
69         def line(self):
70                  return self.stack[-1].line
71         def command(self):
72                 return self.stack[-1].command
73
74         def push_file(self, file):
75                 self.stack.append(self.place(file, 0, ""))
76         def pop_file(self):
77                 self.stack.pop()
78         def next_line(self, command):
79                 self.stack[-1].next_line(command)
80         def at(self):
81                 return self.stack[-1].at()
82 loc = location()
83
84 class makerule:
85         def __init__ (self, target):
86                 self.target = target
87                 self.dependency = []
88                 self.actions = []
89
90         def addaction(self, action):
91                 self.actions.append(action)
92
93         def adddependency(self, dependency):
94                 self.dependency.append(dependency)
95
96         def gtarget(self):
97                 return self.target
98
99         def gdependency(self):
100                 return self.dependency
101
102         def gaction(self):
103                 return self.actions
104
105 class option:
106         def __init__ (self, name):
107                 self.name = name
108                 self.loc = 0
109                 self.value = 0
110                 self.set = 0
111                 self.default = 0
112
113         def setvalue(self, value, loc):
114                 if (self.set):
115                         print "Option %s: \n" % self.name
116                         print "Attempt to set %s at %s\n" % (value, loc.at()) 
117                         print "Already set to %s at %s\n" % \
118                                         (self.value, self.loc.at())
119                         sys.exit(1)
120                 self.set = 1
121                 self.value = value
122                 self.loc = loc
123
124
125         def getvalue(self):
126                 self.set = 1
127                 return self.value
128
129         def setdefault(self, value, loc):
130                 if (self.default):
131                         print "%s: " % self.name
132                         print "Attempt to default %s at %s\n" % (value, loc) 
133                         print "Already defaulted to %s at %s\n" %  \
134                                         (self.value, self.loc.at())
135                         print "Warning only\n"
136                 if (self.set):
137                         print "%s: " % self.name
138                         print "Attempt to default %s at %s\n" % (value, loc) 
139                         print "Already set to %s at %s\n" % \
140                                         (self.value, self.loc.at())
141                         print "Warning only\n"
142                         return
143                 self.default = 1
144                 self.value = value
145                 self.loc = loc
146         def where(self):
147                 return self.loc
148
149
150 class partobj:
151         def __init__ (self, dir, parent, type):
152                 global partinstance
153                 print "partobj dir %s parent %s type %s" %(dir,parent,type)
154                 self.children = []
155                 self.initcode = []
156                 self.registercode = []
157                 self.siblings = 0
158                 self.type = type
159                 self.objects = []
160                 self.dir = dir
161                 self.irq = 0
162                 self.instance = partinstance + 1
163                 partinstance = partinstance + 1
164                 self.devfn = 0  
165                 self.private = 0        
166                 if (parent):
167                         print "add to parent"
168                         self.parent   = parent
169                         parent.children.append(self)
170                 else:
171                         self.parent = self
172
173         def dumpme(self, lvl):
174                 print "%d: type %s" % (lvl, self.type)
175                 print "%d: dir %s" % (lvl,self.dir)
176                 print "%d: parent %s" % (lvl,self.parent.type)
177                 print "%d: parent dir %s" % (lvl,self.parent.dir)
178                 print "%d: initcode " % lvl
179                 for i in self.initcode:
180                         print "  %s\n" % i
181                 print "%d: registercode " % lvl
182                 for i in self.registercode:
183                         print "  %s\n" % i
184
185         def gencode(self):
186                 print "struct cdev dev%d = {" % self.instance
187                 print "/* %s %s */" % (self.type, self.dir)
188                 print "  .devfn = %d" % self.devfn
189                 if (self.siblings):
190                         print "  .next = &dev%d" % self.sibling.instance
191                 if (self.children):
192                         print "  .children = &dev%d" %  \
193                                         self.children[0].instance
194                 if (self.private):
195                         print "  .private = private%d" % self.instance
196                 print "};"
197
198                 
199         def irq(self, irq):
200                 self.irq = irq
201        
202         def addinit(self, code):
203                 self.initcode.append(code)
204                 
205         def addregister(self, code):
206                 self.registercode.append(code)
207                 
208         
209 class partsstack:
210         def __init__ (self):
211                 self.stack = []
212
213         def push(self, part):
214                 self.stack.append(part)
215
216         def pop(self):
217                 return self.stack.pop()
218
219         def tos(self):
220                 return self.stack[-1]
221 pstack = partsstack()
222
223 def fatal(string):      
224         global loc
225         size = len(loc.stack)
226         i = 0
227         while(i < size -1): 
228                 print loc.stack[i].at()
229                 i = i + 1
230         print "%s: %s"% (loc.at(), string)
231         sys.exit(1)
232
233 def warning(string):
234         global loc
235         print "===> Warning:"
236         size = len(loc.stack)
237         i = 0
238         while(i < size -1):
239                 print loc.stack[i].at()
240                 i = i + 1
241         print "%s: %s"% (loc.at(), string)
242
243
244 # -----------------------------------------------------------------------------
245 #                    statements 
246 # -----------------------------------------------------------------------------
247
248 def getvalue(dict, name):
249     if name not in dict.keys(): print 'Undefined:', name
250     v = dict.get(name, 0)
251     if (debug > 1):
252         print "getvalue %s returning %s\n" % (name, v)
253     return v
254
255 def setvalue(dict, name, value):
256         print "name %s value %s" % (name, value)
257         if name in dict.keys(): print "Warning, %s previously defined" % name
258         if (debug > 1):
259                 print "setvalue sets %s to %s\n" % (name, value)
260         dict[name] = value
261
262 # options. 
263 # to create an option, it has to no exist. 
264 # When an option value is fetched, the fact that it was used is 
265 # remembered. 
266 # Legal things to do:
267 # set a default value, then set a real value before the option is used.
268 # set a value, try to set a default, default silently fails.
269 # Illegal:
270 # use the value, then try to set the value
271
272 def getoption(name):
273         print "getoption %s" % name
274         o = getvalue(options, name)
275         if (o == 0):
276                 fatal( "Error. Option %s Undefined. Fix me.\n" % name)
277         if (debug > 2):
278                 print "returns %s" % o
279                 print "%s" % o.where()
280         return o.getvalue()
281
282 # stupid code, refactor later. 
283 def setoption(name, value):
284         o = getvalue(options, name)
285         if (o):
286                 o.setvalue(value, loc)
287                 return
288         o = option(name)
289         o.setvalue(value, loc)
290         setvalue(options, name, o)
291         options_by_order.append(name)
292
293 def setdefault(name, value):
294         o = getvalue(options, name)
295         if (o):
296                 o.setdefault(value, loc)
297                 return
298         print "setdefault: %s not here, setting to %s" % \
299                         (name, value)
300         o = option(name)
301         o.setdefault(value, loc)
302         setvalue(options, name, o)
303         options_by_order.append(name)
304
305 # we do the crt0include as a dictionary, so that if needed we
306 # can trace who added what when. Also it makes the keys
307 # nice and unique. 
308 def addcrt0include(path):
309         global crt0includes
310         #fullpath = os.path.join(curdir, path)
311         #fullpath = path
312         #setvalue(crt0includes, fullpath, loc)
313         # oh shoot. Order matters. All right, we'll worry about this 
314         # later. 
315         fullpath = path
316         if (debug > 2):
317                 print "ADDCRT0: %s\n" % fullpath
318         crt0includes.append(fullpath)
319
320 def addldscript(path):
321         global ldscripts
322         if (path[0] == '/'):
323                 fullpath =  treetop + '/src/' + path
324         else:
325                 fullpath = curdir + '/' + path
326         #fullpath = os.path.join(curdir, path)
327         #setvalue(ldscripts, fullpath, loc)
328         if (debug):
329                 print "fullpath :%s: curdir :%s: path :%s:\n" % (fullpath, curdir, path)
330         ldscripts.append(fullpath)
331
332 def payload(path):
333         global payloadfile
334         adduserdefine("PAYLOAD:=%s"%path)
335 #       addrule('payload')
336 #       adddep('payload', path)
337 #       addaction('payload', 'cp $< $@')
338
339 # this is called with an an object name. 
340 # the easiest thing to do is add this object to the current 
341 # component.
342 # such kludgery. If the name starts with '.' then make the 
343 # dependency be on ./thing.x gag me.
344 def addobjectdriver(dict, object_name):
345         print "add object object_name %s" % object_name
346         suffix = object_name[-2:]
347         if (suffix == '.o'):
348                 suffix = '.c'
349         base = object_name[:-2]
350         if (object_name[0] == '.'):
351                 source = base + suffix
352         else:
353                 source = os.path.join(curdir, base + suffix)
354         object = base + '.o'
355         print "addobject %s source %s\n" % (object, source)
356         setvalue(dict, base, [object, source])
357
358 def addobject(object_name):
359         addobjectdriver(objectrules, object_name)
360
361 def adddriver(driver_name):
362         addobjectdriver(driverrules, driver_name)
363
364 def target(targ_name):
365         global target_dir
366         global curpart
367         print "TARGET loc.file is %s\n" % loc.file()
368         target_dir = os.path.join(os.path.dirname(loc.file()), targ_name)
369         print "TARGET dir.loc.file is %s\n" % os.path.dirname(loc.file())
370         if not os.path.isdir(target_dir):
371                 print 'Creating directory', target_dir
372                 os.makedirs(target_dir)
373         print 'Will place Makefile, crt0.S, etc. in ', target_dir
374         print '%s\n' % loc.file()
375         board = partobj(target_dir, 0, 'board')
376         curpart = board
377
378
379
380 def part(name, path, file):
381         global curpart,curdir
382         if (debug):
383                 print "%s " % name
384         dirstack.append(curdir)
385         curdir = os.path.join(treetop, 'src', name, path)
386         newpart = partobj(curdir, curpart, name)
387         print "PUSH part " , curpart.dir
388         pstack.push(curpart)
389         curpart = newpart
390         #       option(parts, name, path)
391         # open the file, and parse it. 
392 #        curpart.option('MAINBOARD_PART_NUMBER', 
393 #                       os.path.basename(lookup(parts, 'mainboard')))
394 #        option(options, 'MAINBOARD_VENDOR', os.path.dirname(getvalue(parts, 'mainboard')))
395
396         doconfigfile(curdir, file)
397
398 def partpop():
399         global curpart,curdir
400         curpart = pstack.pop()
401         curdir = dirstack.pop()
402         print "POP PART %s\n" % curpart.dir
403
404 # dodir is like part but there is no new part
405 def dodir(path, file):
406         global curdir,  treetop
407         # if the first char is '/', it is relative to treetop, 
408         # else relative to curdir
409         # os.path.join screws up if the name starts with '/', sigh.
410         if (path[0] == '/'):
411                 fullpath = treetop + '/src/' + path 
412         else:
413                 fullpath = os.path.join(curdir,  path)
414         if (debug):
415                 print "DODIR: path %s, fullpath %s\n" % (path, fullpath)
416                 print "DODIR: curdis %s treetop %s\n" % (curdir, treetop)
417         dirstack.append(curdir)
418         curdir = fullpath
419         file = os.path.join(fullpath, file)
420         config_file_list.append(file)
421         doconfigfile(fullpath, file)
422         curdir = dirstack.pop()
423
424 def ternary(expr, yes, no):
425         print "ternary %s" % expr
426         a = tohex(expr) # expr # eval(expr)
427         print "expr %s a %d yes %d no %d\n"% (expr, a, yes, no)
428         if (a == 0):
429             print "Ternary returns %d\n" % yes
430             return yes
431         else:
432             print "Ternary returns %d\n" % no
433             return no
434 # atoi is in the python library, but not strtol? Weird!
435 def tohex(name):
436         return eval('int(%s)' % name)
437
438 def IsInt( str ):
439         """ Is the given string an integer?"""
440         try:
441                 num = int(str)
442                 return 1
443         except ValueError:
444                 return 0
445
446 def addrule(id):
447         o = makerule(id)
448         setvalue(makebaserules, id, o)
449         
450 def adduserdefine(str):
451         userdefines.append(str)
452
453 def dequote(str):
454         a = re.sub("^\"", "", str)
455         a = re.sub("\"$", "", a)
456         # highly un-intuitive, need four \!
457         a = re.sub("\\\\\"", "\"", a)
458         return a
459
460 def addaction(id, str):
461         o = getvalue(makebaserules, id)
462         a = dequote(str)
463         o.addaction(a)
464
465 def adddep(id, str):
466         o = getvalue(makebaserules, id)
467         a = dequote(str)
468         o.adddependency(a)
469
470 # If the first part of <path> matches treetop, replace that part with "$(TOP)"
471 def topify(path):
472         global treetop
473         if path[0:len(treetop)] == treetop:
474                 path = path[len(treetop):len(path)]
475                 if (path[0:1] == "/"):
476                         path = path[1:len(path)]
477                 path = "$(TOP)/" + path
478         return path
479
480 # arch is 'different' ... darn it.
481 def set_arch(my_arch):
482         global arch, makebase
483         global curdir
484         arch = my_arch
485         setdefault('ARCH', my_arch)
486         part('arch', my_arch, 'config/make.base.lb')
487
488
489 def mainboard(path):
490         global mainboard_dir
491         mainboard_dir = path
492         full_mainboard_dir = os.path.join(treetop, 'src/mainboard', path)
493         setdefault('MAINBOARD', full_mainboard_dir)
494         vendor = re.sub("/.*", "", path)
495         mainboard_part_number = re.sub("[^/]/", "", path)
496         setdefault('MAINBOARD_VENDOR', vendor)
497         setdefault('MAINBOARD_PART_NUMBER', mainboard_part_number)
498         part('mainboard', path, 'Config.lb')
499 #=============================================================================
500 #               FILE OUTPUT 
501 #=============================================================================
502 def writemakefileheader(file, fname):
503         file.write("# File: %s\n" % fname)
504         file.write("# This file was generated by '%s %s %s'\n\n"
505                 % (sys.argv[0], sys.argv[1], sys.argv[2]))
506
507
508 def writemakefilesettings(path):
509         global treetop, arch, mainboard_dir, target_dir, options
510         # Write Makefile.settings to seperate the settings
511         # from the actual makefile creation
512         # In practice you need to rerun NLBConfig.py to change
513         # these but in theory you shouldn't need to.
514
515         filename = os.path.join(path, "Makefile.settings")
516         print "Creating", filename
517         file = open(filename, 'w+')
518         writemakefileheader(file, filename)
519         file.write("TOP:=%s\n" % (treetop))
520         #file.write("ARCH:=%s\n" % (arch))
521         #file.write("MAINBOARD:=%s\n" % (mainboard_dir))
522         file.write("TARGET_DIR:=%s\n" % (target_dir))
523         for i in options_by_order:
524                 o = options[i]
525                 # get the number in hex
526                 v =  o.getvalue()
527                 if IsInt(v):
528                         vi = int(v)
529                         s = "export %s:=0x%x\n"% (i, vi)
530                         file.write(s)
531                 else:
532                         file.write("export %s:=%s\n" % (i, v))
533         file.write("export VARIABLES := ");
534         for i in options.keys():
535                 file.write("%s " % i)
536         file.write("\n");
537 #       file.write("CPUFLAGS := ");
538 #       for i in options.keys():
539 #               o = options[i]
540 #               file.write("-D%s=%s " % (i, o.getvalue()))
541 #       file.write("\n");
542         file.close();
543
544
545 # write the makefile
546 # let's try the Makefile
547 # first, dump all the -D stuff
548
549 def writemakefile(path):
550         makefilepath = os.path.join(path, "Makefile")
551         print "Creating", makefilepath
552         file = open(makefilepath, 'w+')
553         writemakefileheader(file, makefilepath)
554
555         # file.write("include Makefile.settings\n")
556         # file.write("include cpuflags\n")
557         # Putting "include cpuflags" in the Makefile has the problem that the
558         # cpuflags file would be generated _after_ we want to include it.
559         # Instead, let make do the work of computing CPUFLAGS:
560         file.write("""\
561 # Get the value of TOP, VARIABLES, and several other variables.
562 include Makefile.settings
563
564 # Function to create an item like -Di586 or -DMAX_CPUS='1' or -Ui686
565 D_item = $(if $(subst undefined,,$(origin $1)),-D$1$(if $($1),='$($1)',),-U$1)
566
567 # Compute the value of CPUFLAGS here during make's first pass.
568 CPUFLAGS := $(foreach _var_,$(VARIABLES),$(call D_item,$(_var_)))
569 """)
570
571         for i in userdefines:
572                 file.write("%s\n" %i)
573         file.write("\n");
574
575         # print out all the object dependencies
576         file.write("\n# object dependencies (objectrules:)\n")
577         file.write("OBJECTS :=\n")
578         file.write("DRIVERS :=\n")
579         for objrule in objectrules.keys():
580                 obj = objectrules[objrule]
581                 obj_name = obj[0]
582                 obj_source = obj[1]
583                 file.write("OBJECTS-1 += %s\n" % (obj_name))
584
585         for driverrule in driverrules.keys():
586                 driver = driverrules[driverrule]
587                 obj_name = driver[0]
588                 obj_source = driver[1]
589                 file.write("DRIVER += %s\n" % (obj_name))
590
591         # Print out all ldscript.ld dependencies.
592         file.write("\n# ldscript.ld dependencies:\n")
593         file.write("LDSUBSCRIPTS-1 := \n" )
594         for script in ldscripts:
595                 file.write("LDSUBSCRIPTS-1 += %s\n" % topify(script))
596
597         # Print out the dependencies for crt0_includes.h
598         file.write("\n# Dependencies for crt0_includes.h\n")
599         file.write("CRT0_INCLUDES:=\n")
600         for i in crt0includes:
601                 if (local_path.match(i)):
602                         file.write("CRT0_INCLUDES += %s\n" % i)
603                 else:
604                         file.write("CRT0_INCLUDES += $(TOP)/src/%s\n" % i)
605
606
607
608                 
609         file.write("\nSOURCES=\n")
610         #for source in sources:
611                 #file.write("SOURCES += %s\n" % source)
612         
613         # Print out the user defines.
614         file.write("\n# userdefines:\n")
615         #for udef in userdefines:
616                 #file.write("%s\n" % udef)
617                 
618         # Print out the base rules.
619         # Need to have a rule that counts on 'all'.
620         file.write("\n# mainrulelist:")
621         #file.write("\nmainrule: %s\n" % mainrulelist)
622
623         # Print out any user rules.
624         file.write("\n# From makerule or docipl commands:\n")
625         # Old way (hash order): for target in makebaserules.keys():
626         # New way (config file order):
627         #for target in makerule_targets:
628                 #makebaserules[target].write(file)
629
630         file.write("\n# objectrules:\n")
631         for objrule in objectrules.keys():
632                 obj = objectrules[objrule]
633                 source = topify(obj[1])
634                 file.write("%s: %s\n" % (obj[0], source))
635                 file.write("\t$(CC) -c $(CFLAGS) -o $@ $<\n")
636                 #file.write("%s\n" % objrule[2])
637
638         for driverrule in driverrules.keys():
639                 driver = driverrules[driverrule]
640                 source = topify(driver[1])
641                 file.write("%s: %s\n" % (driver[0], source))
642                 #file.write("%s\n" % objrule[2])
643
644         # Print out the rules that will make cause the files
645         # generated by NLBConfig.py to be remade if any dependencies change.
646
647         file.write("\n# Remember the automatically generated files\n")
648         file.write("GENERATED:=\n")
649         for genfile in [ 'Makefile',
650                         'Makefile.settings',
651                         'crt0_includes.h',
652                         'nsuperio.c',
653                          'chip.c', 
654                         'LinuxBIOSDoc.config' ]:
655                 file.write("GENERATED += %s\n" % genfile)
656
657         file.write("\n# Remake Makefile (and the other files generated by\n")
658         file.write("# NLBConfig.py) if any config dependencies change.\n")
659
660         for cfile in config_file_list:
661                 file.write("$(GENERATED): %s\n" % topify(cfile))
662
663         for depfile in [ '%s' % top_config_file,    # This a duplicate, remove?
664                         '$(TOP)/util/config/NLBConfig.py',
665                         '$(TOP)/src/arch/$(ARCH)/config/make.base' ]:
666                 file.write("$(GENERATED): %s\n" % depfile)
667
668         file.write("$(GENERATED):\n")
669         file.write("\tpython $(TOP)/util/config/NLBConfig.py %s $(TOP)\n"
670                         % top_config_file)
671
672         keys = makeoptions.keys()
673         keys.sort()
674         file.write("\necho:\n")
675         for key in keys:
676                  file.write("\t@echo %s='$(%s)'\n"% (key,key))
677         
678
679         for i in makebaserules.keys():
680                 m = makebaserules[i]
681                 file.write("%s: " %i)
682                 for i in m.dependency:
683                         file.write("%s " % i)
684                 file.write("\n")
685                 for i in m.actions:
686                         file.write("\t%s\n" % i)
687         file.close();
688
689 # Write out crt0_includes.h (top-level assembly language) include file.
690 def writecrt0_includes(path):
691         crt0filepath = os.path.join(path, "crt0_includes.h")
692         print "Creating", crt0filepath
693         file = open(crt0filepath, 'w+')
694
695         for i in crt0includes:
696                 file.write("#include <%s>\n" % i)
697
698         file.close();
699
700
701 %%
702 parser Config:
703     ignore:      r'\s+'
704     ignore:      "#.*?\r?\n"
705     token NUM:   r'[0-9]+'
706     token XNUM:   r'0x[0-9a-fA-F]+'
707 # Why is path separate? Because paths to resources have to at least
708 # have a slash, we thinks
709     token PATH:    r'[a-zA-Z0-9_.][a-zA-Z0-9/_.]+[a-zA-Z0-9_.]+'
710 # Dir's on the other hand are abitrary
711 # this may all be stupid.
712     token DIRPATH:    r'[a-zA-Z0-9_$()./]+'
713     token ID:    r'[a-zA-Z_.]+[a-zA-Z0-9_.]*'
714     token STR:   r'"([^\\"]+|\\.)*"'
715     token RAWTEXT: r'.*'
716     token OPTION: 'option'
717     token MAINBOARD: 'mainboard'
718     token MAINBOARDINIT: 'mainboardinit'
719     token EQ: '='
720     token END: '$|end'
721     token TARGET: 'target'
722     token OBJECT: 'object'
723     token DRIVER: 'driver'
724     token NORTHBRIDGE: 'northbridge'
725     token SOUTHBRIDGE: 'southbridge'
726     token SUPERIO: 'superio'
727     token IF: 'if'
728     token MAKERULE: 'makerule'
729     token DEP: 'dep'
730     token ACT: 'act'
731     token MAKEDEFINE: 'makedefine'
732     token ADDACTION: 'addaction'
733     token DEFAULT: 'default'
734     token INIT: 'init'
735     token REGISTER: 'register'
736     token CPU: 'cpu'
737     token ARCH: 'arch'
738     token DIR: 'dir'
739     token LDSCRIPT: 'ldscript'
740     token PAYLOAD: 'payload'
741
742     # An expression is the sum and difference of factors
743     rule expr<<V>>:   factor<<V>>         {{ n = factor }}
744                      ( "[+]" factor<<V>>  {{ n = n+factor }}
745                      |  "-"  factor<<V>>  {{ n = n-factor }}
746                      )*                   {{ return n }}
747
748     # A factor is the product and division of terms
749     rule factor<<V>>: term<<V>>           {{ v = term }}
750                      ( "[*]" term<<V>>    {{ v = v*term }}
751                      |  "/"  term<<V>>    {{ v = v/term }}
752                      |  "<<"  term<<V>>    {{ v = v << term }}
753                      |  ">=" term<<V>>    {{ v = (v < term)}}
754                      )*                   {{ return v }}
755
756     rule unop<<V>>: "!" ID                     {{ return ternary(getoption(ID), 1, 0)}}
757     # A term is a number, variable, or an expression surrounded by parentheses
758     rule term<<V>>:
759                  NUM                      {{ return atoi(NUM) }}
760                | XNUM                      {{ return tohex(XNUM) }}
761                | ID                      {{ return tohex(getoption(ID)) }}
762                | unop<<V>>                 {{ return unop }}
763                | "\\(" expr<<V>> "\\)"         {{ return expr }}
764
765     rule option<<C>>: OPTION ID EQ 
766                                 (
767                         STR {{ if (C): setoption(ID, dequote(STR)) }} 
768                         |       term<<[]>> {{ if (C): setoption(ID, term) }}
769                         )
770     rule default<<C>>: DEFAULT ID EQ RAWTEXT {{ if (C): setdefault(ID, RAWTEXT) }}
771
772     rule partend<<C>>: partstmts<<C>> END  
773     rule mainboard: MAINBOARD PATH {{mainboard(PATH) }} 
774                                 partend<<1>>
775                         
776     rule northbridge<<C>>: NORTHBRIDGE PATH 
777                         {{if (C): part('northbridge', PATH, 'Config.lb')}} partend<<C>>
778     rule superio<<C>>: SUPERIO PATH 
779                         {{if (C): part('superio', PATH, 'Config.lb')}} partend<<C>>
780     rule cpu<<C>>: CPU ID 
781                         {{if (C): part('cpu', ID, 'Config.lb')}} partend<<C>>
782     rule arch<<C>>: ARCH ID 
783                         {{if (C): set_arch(ID) }} partend<<C>>
784     rule southbridge<<C>>: SOUTHBRIDGE PATH 
785                         {{if (C): part('southbridge', PATH, 'Config.lb')}} partend<<C>>
786
787     rule mainboardinit<<C>>: 
788                  MAINBOARDINIT DIRPATH {{ if (C): addcrt0include(DIRPATH)}}
789
790     rule object<<C>>: OBJECT DIRPATH {{if (C): addobject(DIRPATH)}}
791     rule driver<<C>>: DRIVER DIRPATH {{if (C): adddriver(DIRPATH)}}
792     rule dir<<C>>:      DIR DIRPATH  {{if (C): dodir(DIRPATH, 'Config.lb') }}
793
794     rule ldscript<<C>>: LDSCRIPT DIRPATH {{if (C): addldscript(DIRPATH) }}
795     rule payload<<C>>: PAYLOAD DIRPATH {{if (C): payload(DIRPATH) }}
796 # if is a bad id ....
797     rule iif<<C>>:
798 # needs to be C and ID, but nested if's are, we hope, not going to 
799 # happen. IF so, possibly ID && C could be used.
800                 IF ID {{ c = tohex(getoption(ID)); print "IF %d\n" % c }} (stmt<<c>>)* END
801
802     rule depsacts<<ID, C>>: (
803                         DEP  STR {{ if (C): adddep(ID, STR) }}
804                         | ACT STR {{ if (C): addaction(ID, STR) }}
805                         )*
806     rule makerule<<C>>: MAKERULE DIRPATH {{ if (C): addrule(DIRPATH) }} 
807                         depsacts<<DIRPATH, C>> 
808     rule makedefine<<C>>: MAKEDEFINE RAWTEXT
809                          {{ if (C): adduserdefine(RAWTEXT) }}
810     rule addaction<<C>>: ADDACTION ID STR
811                          {{ if (C): addaction(ID, STR) }}
812     rule init<<C>>:   INIT  STR  {{ if (C): curpart.addinit(STR) }}
813     rule register<<C>>:   REGISTER  STR  {{ if (C): curpart.addregister(STR) }}
814
815 # to make if work without 2 passses, we use an old hack from SIMD, the 
816 # context bit. If the bit is 1, then ops get done, otherwise
817 # ops don't get done. From the top level, context is always
818 # 1. In an if, context depends on eval of the if condition
819     rule stmt<<C>>:   
820                   option<<C>>             {{ return option }}
821                 | default<<C>>    {{ return default }}
822                 | cpu<<C>>          {{ return cpu}}
823                 | arch<<C>>          {{ return arch}}
824                 | northbridge<<C>>        {{ return northbridge }}
825                 | southbridge<<C>>        {{ return southbridge }}
826                 | superio<<C>>    {{ return superio }}
827                 | object<<C>>     {{ return object }}
828                 | driver<<C>>     {{ return driver }}
829                 | mainboardinit<<C>>   {{ return mainboardinit }}
830                 | makerule<<C>>           {{ return makerule }}
831                 | makedefine<<C>>         {{ return makedefine }}
832                 | addaction<<C>>          {{ return addaction }}
833                 | init<<C>>               {{ return init }}
834                 | register<<C>>                   {{ return register}}
835                 | iif<<C>>        {{ return iif }}
836                 | dir<<C>>              {{ return dir}}
837                 | ldscript<<C>>         {{ return ldscript}}
838                 | payload<<C>>          {{ return payload}}
839
840     rule stmts<<C>>: (stmt<<C>>)*               {{  }}
841
842     rule partstmts<<C>>: (stmt<<C>>)*           {{  partpop()}}
843 # need this to get from python to the rules, I think.
844
845     rule pstmts: stmts<<1>>                     {{ }}
846     rule target: TARGET DIRPATH            {{target(DIRPATH)}}
847     rule board: target mainboard   {{ }}
848 %%
849
850 def dumptree(part, lvl):
851         print "DUMPTREE ME is"
852         part.dumpme(lvl)
853         # dump the siblings -- actually are there any? not sure
854         # dump the kids
855         print "DUMPTREE KIDS are"
856         for kid in part.children:
857                 dumptree(kid, lvl+1)
858         print "DONE DUMPTREE"
859
860 def gencode(part):
861         print "GENCODE ME is"
862         part.gencode()
863         # dump the siblings -- actually are there any? not sure
864         # dump the kids
865         print "GENCODE KIDS are"
866         for kid in part.children:
867                 gencode(kid)
868         print "DONE GENCODE"
869         
870
871 def doconfigfile(path, file):
872         if (debug):
873                 print "DOCONFIGFILE", path, " ", file
874         filename = os.path.join(path, file)
875         loc.push_file(filename);
876         parse('pstmts', open(filename, 'r').read())
877
878 if __name__=='__main__':
879     from sys import argv
880     if (len(argv) < 3):
881         print 'Args: <file> <path to linuxbios>'
882
883     top_config_file = os.path.abspath(sys.argv[1])
884
885     treetop = os.path.abspath(sys.argv[2])
886
887     # Set the default locations for config files.
888     makebase = os.path.join(treetop, "util/config/make.base")
889     crt0base = os.path.join(treetop, "arch/i386/config/crt0.base")
890     doxyscriptbase = os.path.join(treetop, "src/config/doxyscript.base")
891     
892     # Now read in the customizing script...
893     loc.push_file(argv[1]);
894     parse('board', open(argv[1], 'r').read())
895     dumptree(curpart, 0)
896     gencode(curpart)
897     for i in options.keys():
898         o = options[i]
899         print "key %s @%s: val %s" % (i, o.where(), o.getvalue())
900     # crt0 includes
901     for i in crt0includes:
902         print "crt0include file %s \n" % (i)
903     for i in driverrules.keys():
904         print "driver file %s \n" % (i)
905     for i in ldscripts:
906         print "ldscript file %s\n" % (i)
907     for i in makebaserules.keys():
908         m = makebaserules[i]
909         print " makerule %s dep %s act %s\n" % (i, m.dependency, m.actions)
910     writemakefilesettings(target_dir)
911     writecrt0_includes(target_dir)
912     writemakefile(target_dir)