Replace sconfig with a C implementation.
(smaller, faster, standard parser generator, no more python) Provide precompiled parser, so bison and flex are optional dependencies. Adapt Makefile and abuild (which uses some sconfig file as a magic path) to match. Drop python as dependency from README, and add bison and flex as optional dependencies Signed-off-by: Patrick Georgi <patrick.georgi@coresystems.de> Acked-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Ronald G. Minnich <rminnich@gmail.com> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5373 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
56a684a2ee
commit
7e8c9aa271
15
Makefile
15
Makefile
|
@ -37,9 +37,6 @@ export src := src
|
||||||
export srck := $(top)/util/kconfig
|
export srck := $(top)/util/kconfig
|
||||||
export obj ?= build
|
export obj ?= build
|
||||||
export objk := $(obj)/util/kconfig
|
export objk := $(obj)/util/kconfig
|
||||||
export sconfig := $(top)/util/sconfig
|
|
||||||
export yapps2_py := $(sconfig)/yapps2.py
|
|
||||||
export config_g := $(sconfig)/config.g
|
|
||||||
|
|
||||||
|
|
||||||
export KERNELVERSION := 4.0
|
export KERNELVERSION := 4.0
|
||||||
|
@ -109,7 +106,7 @@ PLATFORM-y += src/arch/$(ARCHDIR-y) src/cpu src/mainboard/$(MAINBOARDDIR)
|
||||||
TARGETS-y :=
|
TARGETS-y :=
|
||||||
|
|
||||||
BUILD-y := src/lib src/boot src/console src/devices src/southbridge src/northbridge src/superio src/drivers
|
BUILD-y := src/lib src/boot src/console src/devices src/southbridge src/northbridge src/superio src/drivers
|
||||||
BUILD-y += util/cbfstool
|
BUILD-y += util/cbfstool util/sconfig
|
||||||
BUILD-$(CONFIG_ARCH_X86) += src/pc80
|
BUILD-$(CONFIG_ARCH_X86) += src/pc80
|
||||||
|
|
||||||
ifneq ($(CONFIG_LOCALVERSION),"")
|
ifneq ($(CONFIG_LOCALVERSION),"")
|
||||||
|
@ -150,16 +147,11 @@ $(obj)/config.h:
|
||||||
|
|
||||||
CBFSTOOL:=$(obj)/util/cbfstool/cbfstool
|
CBFSTOOL:=$(obj)/util/cbfstool/cbfstool
|
||||||
|
|
||||||
$(obj)/mainboard/$(MAINBOARDDIR)/config.py: $(yapps2_py) $(config_g)
|
|
||||||
mkdir -p $(obj)/mainboard/$(MAINBOARDDIR)
|
|
||||||
python $(yapps2_py) $(config_g) $(obj)/mainboard/$(MAINBOARDDIR)/config.py
|
|
||||||
|
|
||||||
|
|
||||||
# needed objects that every mainboard uses
|
# needed objects that every mainboard uses
|
||||||
# Creation of these is architecture and mainboard independent
|
# Creation of these is architecture and mainboard independent
|
||||||
$(obj)/mainboard/$(MAINBOARDDIR)/static.c: $(src)/mainboard/$(MAINBOARDDIR)/devicetree.cb $(obj)/mainboard/$(MAINBOARDDIR)/config.py
|
$(obj)/mainboard/$(MAINBOARDDIR)/static.c: $(src)/mainboard/$(MAINBOARDDIR)/devicetree.cb $(obj)/util/sconfig/sconfig
|
||||||
mkdir -p $(obj)/mainboard/$(MAINBOARDDIR)
|
mkdir -p $(obj)/mainboard/$(MAINBOARDDIR)
|
||||||
(PYTHONPATH=$(top)/util/sconfig python $(obj)/mainboard/$(MAINBOARDDIR)/config.py $(MAINBOARDDIR) $(top) $(obj)/mainboard/$(MAINBOARDDIR))
|
$(obj)/util/sconfig/sconfig $(MAINBOARDDIR) $(obj)/mainboard/$(MAINBOARDDIR)
|
||||||
|
|
||||||
objs:=$(obj)/mainboard/$(MAINBOARDDIR)/static.o
|
objs:=$(obj)/mainboard/$(MAINBOARDDIR)/static.o
|
||||||
initobjs:=
|
initobjs:=
|
||||||
|
@ -334,7 +326,6 @@ clean-for-update: doxygen-clean
|
||||||
rm -f $(obj)/mainboard/$(MAINBOARDDIR)/bootblock.* $(obj)/mainboard/$(MAINBOARDDIR)/dsdt.*
|
rm -f $(obj)/mainboard/$(MAINBOARDDIR)/bootblock.* $(obj)/mainboard/$(MAINBOARDDIR)/dsdt.*
|
||||||
rm -f $(obj)/cpu/x86/smm/smm_bin.c $(obj)/cpu/x86/smm/smm.* $(obj)/cpu/x86/smm/smm
|
rm -f $(obj)/cpu/x86/smm/smm_bin.c $(obj)/cpu/x86/smm/smm.* $(obj)/cpu/x86/smm/smm
|
||||||
rmdir -p $(alldirs) 2>/dev/null >/dev/null || true
|
rmdir -p $(alldirs) 2>/dev/null >/dev/null || true
|
||||||
$(MAKE) -C util/sconfig clean
|
|
||||||
|
|
||||||
clean: clean-for-update
|
clean: clean-for-update
|
||||||
rm -f $(obj)/coreboot* .ccwrap
|
rm -f $(obj)/coreboot* .ccwrap
|
||||||
|
|
2
README
2
README
|
@ -34,7 +34,6 @@ Build Requirements
|
||||||
|
|
||||||
* gcc / g++
|
* gcc / g++
|
||||||
* make
|
* make
|
||||||
* python
|
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
|
@ -42,6 +41,7 @@ Optional:
|
||||||
* iasl (for targets with ACPI support)
|
* iasl (for targets with ACPI support)
|
||||||
* gdb (for better debugging facilities on some targets)
|
* gdb (for better debugging facilities on some targets)
|
||||||
* ncurses (for 'make menuconfig')
|
* ncurses (for 'make menuconfig')
|
||||||
|
* flex and bison (for regenerating parsers)
|
||||||
|
|
||||||
|
|
||||||
Building coreboot
|
Building coreboot
|
||||||
|
|
|
@ -558,8 +558,8 @@ target=""
|
||||||
buildall=false
|
buildall=false
|
||||||
verbose=false
|
verbose=false
|
||||||
|
|
||||||
test -f util/sconfig/config.g && ROOT=$( pwd )
|
test -f util/sconfig/sconfig.l && ROOT=$( pwd )
|
||||||
test -f ../util/sconfig/config.g && ROOT=$( cd ..; pwd )
|
test -f ../util/sconfig/sconfig.l && ROOT=$( cd ..; pwd )
|
||||||
test "$ROOT" = "" && ROOT=$( cd ../..; pwd )
|
test "$ROOT" = "" && ROOT=$( cd ../..; pwd )
|
||||||
|
|
||||||
# parse parameters.. try to find out whether we're running GNU getopt
|
# parse parameters.. try to find out whether we're running GNU getopt
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,31 +0,0 @@
|
||||||
ALL: $(shell echo *.g | sed s/\\.g/\\.py/g )
|
|
||||||
|
|
||||||
%.py: %.g yapps2.py yappsrt.py Makefile
|
|
||||||
python yapps2.py $<
|
|
||||||
|
|
||||||
DOC: yapps2.ps yapps2.pdf manual/index.html
|
|
||||||
|
|
||||||
yapps2.ps: yapps2.dvi
|
|
||||||
dvips -q yapps2.dvi -o yapps2.ps
|
|
||||||
|
|
||||||
yapps2.pdf: yapps2.ps
|
|
||||||
ps2pdf yapps2.ps
|
|
||||||
|
|
||||||
yapps2.dvi: yapps2.tex
|
|
||||||
latex yapps2.tex
|
|
||||||
|
|
||||||
manual/index.html: yapps2.aux yapps2.tex
|
|
||||||
rm manual/yapps2.css
|
|
||||||
latex2html -dir 'manual' -mkdir -lcase_tags -font_size 12pt -split 4 -toc_depth 4 -html_version 4.0,unicode,table -t 'Yapps 2.0 Manual' -address 'Amit J Patel, amitp@cs.stanford.edu' -info 0 -show_section_numbers -up_title 'Yapps Page' -up_url 'http://theory.stanford.edu/~amitp/yapps/' -strict -image_type png yapps2.tex
|
|
||||||
echo '@import url("http://www-cs-students.stanford.edu/~amitp/amitp.css");' > manual/yapps2-new.css
|
|
||||||
echo 'hr { display:none; }' >> manual/yapps2-new.css
|
|
||||||
echo 'h1 br, h2 br { display:none; }' >>manual/yapps2-new.css
|
|
||||||
cat manual/yapps2.css >> manual/yapps2-new.css
|
|
||||||
rm manual/yapps2.css
|
|
||||||
mv manual/yapps2-new.css manual/yapps2.css
|
|
||||||
|
|
||||||
DISTRIB:
|
|
||||||
cd ..; zip -u yapps2.zip yapps2/{LICENSE,yapps2.py,yappsrt.py,parsedesc.g,examples/*.g,NOTES,yapps2.tex,Makefile,manual/*.html,manual/*.css,manual/*.png}
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f config.py yappsrt.pyc parsedesc.py
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
sconfigobj :=
|
||||||
|
sconfigobj += lex.yy.o
|
||||||
|
sconfigobj += sconfig.tab.o
|
||||||
|
|
||||||
|
$(obj)/util/sconfig:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(obj)/util/sconfig/%.o: $(obj)/util/sconfig/%.c
|
||||||
|
printf " HOSTCC $(subst $(obj)/,,$(@))\n"
|
||||||
|
$(HOSTCC) $(SCONFIGFLAGS) $(HOSTCFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
ifdef SCONFIG_GENPARSER
|
||||||
|
$(top)/util/sconfig/lex.yy.c_shipped: $(top)/util/sconfig/sconfig.l
|
||||||
|
flex -o $@ $<
|
||||||
|
|
||||||
|
# the .c rule also creates .h
|
||||||
|
$(top)/util/sconfig/sconfig.tab.h_shipped: $(top)/util/sconfig/sconfig.tab.c_shipped
|
||||||
|
$(top)/util/sconfig/sconfig.tab.c_shipped: $(top)/util/sconfig/sconfig.y
|
||||||
|
bison --defines=$(top)/util/sconfig/sconfig.tab.h_shipped -o $@ $<
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(obj)/util/sconfig/lex.yy.o: $(obj)/util/sconfig/sconfig.tab.h
|
||||||
|
|
||||||
|
$(obj)/util/sconfig/%: $(top)/util/sconfig/%_shipped
|
||||||
|
cp $< $@
|
||||||
|
|
||||||
|
$(obj)/util/sconfig/sconfig: $(obj)/util/sconfig $(addprefix $(obj)/util/sconfig/,$(sconfigobj))
|
||||||
|
printf " HOSTCXX $(subst $(obj)/,,$(@)) (link)\n"
|
||||||
|
$(HOSTCXX) $(SCONFIGFLAGS) -o $@ $(addprefix $(obj)/util/sconfig/,$(sconfigobj))
|
|
@ -1,46 +0,0 @@
|
||||||
April 14, 2002:
|
|
||||||
|
|
||||||
I haven't worked on Yapps for a while, mainly because I spent all my energy
|
|
||||||
on trying to graduate. Now that I've finished school, I have several projects
|
|
||||||
I want to start working on again, including Yapps.
|
|
||||||
|
|
||||||
Notes for myself:
|
|
||||||
|
|
||||||
Add a debugging mode that helps you understand how the grammar
|
|
||||||
is constructed and how things are being parsed
|
|
||||||
Look into an English output mode that would use natural language
|
|
||||||
to describe a grammar
|
|
||||||
Optimize unused variables
|
|
||||||
Add a convenience to automatically gather up the values returned
|
|
||||||
from subpatterns, put them into a list, and return them
|
|
||||||
Improve the documentation
|
|
||||||
Write some larger examples
|
|
||||||
Get rid of old-style regex support
|
|
||||||
Use SRE's lex support to speed up lexing (this may be hard given that
|
|
||||||
yapps allows for context-sensitive lexers)
|
|
||||||
Look over Dan Connoly's experience with Yapps (bugs, frustrations, etc.)
|
|
||||||
and see what improvements could be made
|
|
||||||
Add something to pretty-print the grammar (without the actions)
|
|
||||||
Maybe conditionals? Follow this rule only if <condition> holds.
|
|
||||||
But this would be useful mainly when multiple rules match, and we
|
|
||||||
want the first matching rule. The conditional would mean we skip to
|
|
||||||
the next rule. Maybe this is part of the attribute grammar system,
|
|
||||||
where rule X<0> can be specified separately from X<N>.
|
|
||||||
Convenience functions that could build return values for all rules
|
|
||||||
without specifying the code for each rule individually
|
|
||||||
Patterns (abstractions over rules) -- for example, comma separated values
|
|
||||||
have a certain rule pattern that gets replicated all over the place
|
|
||||||
"Gather" mode that simply outputs the return values for certain nodes.
|
|
||||||
For example, if you just want all expressions, you could ask yapps
|
|
||||||
to gather the results of the 'expr' rule into a list. This would
|
|
||||||
ignore all the higher level structure.
|
|
||||||
Look at everyone's Yapps grammars, and come up with larger examples
|
|
||||||
http://www.w3.org/2000/10/swap/SemEnglish.g
|
|
||||||
http://www.w3.org/2000/10/swap/kifExpr.g
|
|
||||||
http://www.w3.org/2000/10/swap/rdfn3.g
|
|
||||||
It would be nice if you could feed text into Yapps (push model) instead
|
|
||||||
of Yapps reading text out of a string (pull model). However, I think
|
|
||||||
that would make the resulting parser code mostly unreadable
|
|
||||||
(like yacc, etc.). Coroutines/stacklesspython may be the answer.
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,195 +0,0 @@
|
||||||
######################################################################
|
|
||||||
# The remainder of this file is from parsedesc.{g,py}
|
|
||||||
|
|
||||||
def append(lst, x):
|
|
||||||
"Imperative append"
|
|
||||||
lst.append(x)
|
|
||||||
return lst
|
|
||||||
|
|
||||||
def add_inline_token(tokens, str):
|
|
||||||
tokens.insert( 0, (str, eval(str, {}, {})) )
|
|
||||||
return Terminal(str)
|
|
||||||
|
|
||||||
def cleanup_choice(lst):
|
|
||||||
if len(lst) == 0: return Sequence([])
|
|
||||||
if len(lst) == 1: return lst[0]
|
|
||||||
return apply(Choice, tuple(lst))
|
|
||||||
|
|
||||||
def cleanup_sequence(lst):
|
|
||||||
if len(lst) == 1: return lst[0]
|
|
||||||
return apply(Sequence, tuple(lst))
|
|
||||||
|
|
||||||
def cleanup_rep(node, rep):
|
|
||||||
if rep == 'star': return Star(node)
|
|
||||||
elif rep == 'plus': return Plus(node)
|
|
||||||
else: return node
|
|
||||||
|
|
||||||
def resolve_name(tokens, id, args):
|
|
||||||
if id in map(lambda x: x[0], tokens):
|
|
||||||
# It's a token
|
|
||||||
if args:
|
|
||||||
print 'Warning: ignoring parameters on TOKEN %s<<%s>>' % (id, args)
|
|
||||||
return Terminal(id)
|
|
||||||
else:
|
|
||||||
# It's a name, so assume it's a nonterminal
|
|
||||||
return NonTerminal(id, args)
|
|
||||||
|
|
||||||
%%
|
|
||||||
parser ParserDescription:
|
|
||||||
option: "context-insensitive-scanner"
|
|
||||||
|
|
||||||
ignore: "[ \t\r\n]+"
|
|
||||||
ignore: "#.*?\r?\n"
|
|
||||||
token END: "$"
|
|
||||||
token ATTR: "<<.+?>>"
|
|
||||||
token STMT: "{{.+?}}"
|
|
||||||
token ID: '[a-zA-Z_][a-zA-Z_0-9]*'
|
|
||||||
token STR: '[rR]?\'([^\\n\'\\\\]|\\\\.)*\'|[rR]?"([^\\n"\\\\]|\\\\.)*"'
|
|
||||||
token LP: '\\('
|
|
||||||
token RP: '\\)'
|
|
||||||
token LB: '\\['
|
|
||||||
token RB: '\\]'
|
|
||||||
token OR: '[|]'
|
|
||||||
token STAR: '[*]'
|
|
||||||
token PLUS: '[+]'
|
|
||||||
token QUEST: '[?]'
|
|
||||||
token COLON: ':'
|
|
||||||
|
|
||||||
rule Parser: "parser" ID ":"
|
|
||||||
Options
|
|
||||||
Tokens
|
|
||||||
Rules<<Tokens>>
|
|
||||||
END
|
|
||||||
{{ return Generator(ID,Options,Tokens,Rules) }}
|
|
||||||
|
|
||||||
rule Options: {{ opt = {} }}
|
|
||||||
( "option" ":" Str {{ opt[Str] = 1 }} )*
|
|
||||||
{{ return opt }}
|
|
||||||
|
|
||||||
rule Tokens: {{ tok = [] }}
|
|
||||||
(
|
|
||||||
"token" ID ":" Str {{ tok.append( (ID,Str) ) }}
|
|
||||||
| "ignore" ":" Str {{ tok.append( ('#ignore',Str) ) }}
|
|
||||||
)*
|
|
||||||
{{ return tok }}
|
|
||||||
|
|
||||||
rule Rules<<tokens>>:
|
|
||||||
{{ rul = [] }}
|
|
||||||
(
|
|
||||||
"rule" ID OptParam ":" ClauseA<<tokens>>
|
|
||||||
{{ rul.append( (ID,OptParam,ClauseA) ) }}
|
|
||||||
)*
|
|
||||||
{{ return rul }}
|
|
||||||
|
|
||||||
rule ClauseA<<tokens>>:
|
|
||||||
ClauseB<<tokens>>
|
|
||||||
{{ v = [ClauseB] }}
|
|
||||||
( OR ClauseB<<tokens>> {{ v.append(ClauseB) }} )*
|
|
||||||
{{ return cleanup_choice(v) }}
|
|
||||||
|
|
||||||
rule ClauseB<<tokens>>:
|
|
||||||
{{ v = [] }}
|
|
||||||
( ClauseC<<tokens>> {{ v.append(ClauseC) }} )*
|
|
||||||
{{ return cleanup_sequence(v) }}
|
|
||||||
|
|
||||||
rule ClauseC<<tokens>>:
|
|
||||||
ClauseD<<tokens>>
|
|
||||||
( PLUS {{ return Plus(ClauseD) }}
|
|
||||||
| STAR {{ return Star(ClauseD) }}
|
|
||||||
| {{ return ClauseD }} )
|
|
||||||
|
|
||||||
rule ClauseD<<tokens>>:
|
|
||||||
STR {{ t = (STR, eval(STR,{},{})) }}
|
|
||||||
{{ if t not in tokens: tokens.insert( 0, t ) }}
|
|
||||||
{{ return Terminal(STR) }}
|
|
||||||
| ID OptParam {{ return resolve_name(tokens, ID, OptParam) }}
|
|
||||||
| LP ClauseA<<tokens>> RP {{ return ClauseA }}
|
|
||||||
| LB ClauseA<<tokens>> RB {{ return Option(ClauseA) }}
|
|
||||||
| STMT {{ return Eval(STMT[2:-2]) }}
|
|
||||||
|
|
||||||
rule OptParam: [ ATTR {{ return ATTR[2:-2] }} ] {{ return '' }}
|
|
||||||
rule Str: STR {{ return eval(STR,{},{}) }}
|
|
||||||
%%
|
|
||||||
|
|
||||||
# This replaces the default main routine
|
|
||||||
|
|
||||||
yapps_options = [
|
|
||||||
('context-insensitive-scanner', 'context-insensitive-scanner',
|
|
||||||
'Scan all tokens (see docs)')
|
|
||||||
]
|
|
||||||
|
|
||||||
def generate(inputfilename, outputfilename='', dump=0, **flags):
|
|
||||||
"""Generate a grammar, given an input filename (X.g)
|
|
||||||
and an output filename (defaulting to X.py)."""
|
|
||||||
|
|
||||||
if not outputfilename:
|
|
||||||
if inputfilename[-2:]=='.g': outputfilename = inputfilename[:-2]+'.py'
|
|
||||||
else: raise "Invalid Filename", outputfilename
|
|
||||||
|
|
||||||
print ' SCONFIG ', join(outputfilename.split('/')[-4:], '/')
|
|
||||||
|
|
||||||
DIVIDER = '\n%%\n' # This pattern separates the pre/post parsers
|
|
||||||
preparser, postparser = None, None # Code before and after the parser desc
|
|
||||||
|
|
||||||
# Read the entire file
|
|
||||||
s = open(inputfilename,'r').read()
|
|
||||||
|
|
||||||
# See if there's a separation between the pre-parser and parser
|
|
||||||
f = find(s, DIVIDER)
|
|
||||||
if f >= 0: preparser, s = s[:f]+'\n\n', s[f+len(DIVIDER):]
|
|
||||||
|
|
||||||
# See if there's a separation between the parser and post-parser
|
|
||||||
f = find(s, DIVIDER)
|
|
||||||
if f >= 0: s, postparser = s[:f], '\n\n'+s[f+len(DIVIDER):]
|
|
||||||
|
|
||||||
# Create the parser and scanner
|
|
||||||
p = ParserDescription(ParserDescriptionScanner(s))
|
|
||||||
if not p: return
|
|
||||||
|
|
||||||
# Now parse the file
|
|
||||||
t = wrap_error_reporter(p, 'Parser')
|
|
||||||
if not t: return # Error
|
|
||||||
if preparser is not None: t.preparser = preparser
|
|
||||||
if postparser is not None: t.postparser = postparser
|
|
||||||
|
|
||||||
# Check the options
|
|
||||||
for f in t.options.keys():
|
|
||||||
for opt,_,_ in yapps_options:
|
|
||||||
if f == opt: break
|
|
||||||
else:
|
|
||||||
print 'Warning: unrecognized option', f
|
|
||||||
# Add command line options to the set
|
|
||||||
for f in flags.keys(): t.options[f] = flags[f]
|
|
||||||
|
|
||||||
# Generate the output
|
|
||||||
if dump:
|
|
||||||
t.dump_information()
|
|
||||||
else:
|
|
||||||
t.output = open(outputfilename, 'w')
|
|
||||||
t.generate_output()
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
import sys, getopt
|
|
||||||
optlist, args = getopt.getopt(sys.argv[1:], 'f:', ['dump'])
|
|
||||||
if not args or len(args) > 2:
|
|
||||||
print 'Usage:'
|
|
||||||
print ' python', sys.argv[0], '[flags] input.g [output.py]'
|
|
||||||
print 'Flags:'
|
|
||||||
print (' --dump' + ' '*40)[:35] + 'Dump out grammar information'
|
|
||||||
for flag, _, doc in yapps_options:
|
|
||||||
print (' -f' + flag + ' '*40)[:35] + doc
|
|
||||||
else:
|
|
||||||
# Read in the options and create a list of flags
|
|
||||||
flags = {}
|
|
||||||
for opt in optlist:
|
|
||||||
for flag, name, _ in yapps_options:
|
|
||||||
if opt == ('-f', flag):
|
|
||||||
flags[name] = 1
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if opt == ('--dump', ''):
|
|
||||||
flags['dump'] = 1
|
|
||||||
else:
|
|
||||||
print 'Warning - unrecognized option: ', opt[0], opt[1]
|
|
||||||
|
|
||||||
apply(generate, tuple(args), flags)
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
%{
|
||||||
|
/*
|
||||||
|
* sconfig, coreboot device tree compiler
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 coresystems GmbH
|
||||||
|
* written by Patrick Georgi <patrick.georgi@coresystems.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sconfig.tab.h"
|
||||||
|
|
||||||
|
int linenum = 0;
|
||||||
|
%}
|
||||||
|
%option nodebug
|
||||||
|
%%
|
||||||
|
[ \t]+ {}
|
||||||
|
#.*\n {linenum++;}
|
||||||
|
\r?\n {linenum++;}
|
||||||
|
chip {return(CHIP);}
|
||||||
|
device {return(DEVICE);}
|
||||||
|
register {return(REGISTER);}
|
||||||
|
on {yylval.number=1; return(BOOL);}
|
||||||
|
off {yylval.number=0; return(BOOL);}
|
||||||
|
pci {yylval.number=PCI; return(BUS);}
|
||||||
|
pnp {yylval.number=PNP; return(BUS);}
|
||||||
|
i2c {yylval.number=I2C; return(BUS);}
|
||||||
|
apic {yylval.number=APIC; return(BUS);}
|
||||||
|
apic_cluster {yylval.number=APIC_CLUSTER; return(BUS);}
|
||||||
|
pci_domain {yylval.number=PCI_DOMAIN; return(BUS);}
|
||||||
|
irq {yylval.number=IRQ; return(RESOURCE);}
|
||||||
|
drq {yylval.number=DRQ; return(RESOURCE);}
|
||||||
|
io {yylval.number=IO; return(RESOURCE);}
|
||||||
|
end {return(END);}
|
||||||
|
= {return(EQUALS);}
|
||||||
|
0x[0-9a-fA-F.]+ {yylval.string = malloc(yyleng+1); strncpy(yylval.string, yytext, yyleng); yylval.string[yyleng]='\0'; return(NUMBER);}
|
||||||
|
[0-9.]+ {yylval.string = malloc(yyleng+1); strncpy(yylval.string, yytext, yyleng); yylval.string[yyleng]='\0'; return(NUMBER);}
|
||||||
|
[0-9a-fA-F.]+ {yylval.string = malloc(yyleng+1); strncpy(yylval.string, yytext, yyleng); yylval.string[yyleng]='\0'; return(NUMBER);}
|
||||||
|
\"[^\"]+\" {yylval.string = malloc(yyleng-1); strncpy(yylval.string, yytext+1, yyleng-2); yylval.string[yyleng-2]='\0'; return(STRING);}
|
||||||
|
[^ \n\t]+ {yylval.string = malloc(yyleng+1); strncpy(yylval.string, yytext, yyleng); yylval.string[yyleng]='\0'; return(STRING);}
|
||||||
|
%%
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
/* A Bison parser, made by GNU Bison 2.4.1. */
|
||||||
|
|
||||||
|
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||||
|
|
||||||
|
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* As a special exception, you may create a larger work that contains
|
||||||
|
part or all of the Bison parser skeleton and distribute that work
|
||||||
|
under terms of your choice, so long as that work isn't itself a
|
||||||
|
parser generator using the skeleton or a modified version thereof
|
||||||
|
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||||
|
the parser skeleton itself, you may (at your option) remove this
|
||||||
|
special exception, which will cause the skeleton and the resulting
|
||||||
|
Bison output files to be licensed under the GNU General Public
|
||||||
|
License without this special exception.
|
||||||
|
|
||||||
|
This special exception was added by the Free Software Foundation in
|
||||||
|
version 2.2 of Bison. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Tokens. */
|
||||||
|
#ifndef YYTOKENTYPE
|
||||||
|
# define YYTOKENTYPE
|
||||||
|
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||||
|
know about them. */
|
||||||
|
enum yytokentype {
|
||||||
|
CHIP = 258,
|
||||||
|
DEVICE = 259,
|
||||||
|
REGISTER = 260,
|
||||||
|
BOOL = 261,
|
||||||
|
BUS = 262,
|
||||||
|
RESOURCE = 263,
|
||||||
|
END = 264,
|
||||||
|
EQUALS = 265,
|
||||||
|
HEX = 266,
|
||||||
|
STRING = 267,
|
||||||
|
PCI = 268,
|
||||||
|
PNP = 269,
|
||||||
|
I2C = 270,
|
||||||
|
APIC = 271,
|
||||||
|
APIC_CLUSTER = 272,
|
||||||
|
PCI_DOMAIN = 273,
|
||||||
|
IRQ = 274,
|
||||||
|
DRQ = 275,
|
||||||
|
IO = 276,
|
||||||
|
NUMBER = 277
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||||
|
typedef union YYSTYPE
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Line 1676 of yacc.c */
|
||||||
|
#line 125 "/home/Patrick/work/coreboot/util/sconfig/sconfig.y"
|
||||||
|
|
||||||
|
struct device *device;
|
||||||
|
char *string;
|
||||||
|
int number;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Line 1676 of yacc.c */
|
||||||
|
#line 82 "/home/Patrick/work/coreboot/util/sconfig/sconfig.tab.h_shipped"
|
||||||
|
} YYSTYPE;
|
||||||
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
|
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||||
|
# define YYSTYPE_IS_DECLARED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern YYSTYPE yylval;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,499 @@
|
||||||
|
%{
|
||||||
|
/*
|
||||||
|
* sconfig, coreboot device tree compiler
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 coresystems GmbH
|
||||||
|
* written by Patrick Georgi <patrick.georgi@coresystems.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
enum devtype { chip, device };
|
||||||
|
|
||||||
|
struct resource;
|
||||||
|
struct resource {
|
||||||
|
int type;
|
||||||
|
int index;
|
||||||
|
int base;
|
||||||
|
struct resource *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reg;
|
||||||
|
struct reg {
|
||||||
|
char *key;
|
||||||
|
char *value;
|
||||||
|
struct reg *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device;
|
||||||
|
struct device {
|
||||||
|
int id;
|
||||||
|
int enabled;
|
||||||
|
int used;
|
||||||
|
int multidev;
|
||||||
|
int link;
|
||||||
|
int rescnt;
|
||||||
|
int chiph_exists;
|
||||||
|
char *ops;
|
||||||
|
char *name;
|
||||||
|
char *aliased_name;
|
||||||
|
char *name_underscore;
|
||||||
|
char *path;
|
||||||
|
int path_a;
|
||||||
|
int path_b;
|
||||||
|
int bustype;
|
||||||
|
enum devtype type;
|
||||||
|
struct device *parent;
|
||||||
|
struct device *bus;
|
||||||
|
struct device *next;
|
||||||
|
struct device *nextdev;
|
||||||
|
struct device *children;
|
||||||
|
struct device *latestchild;
|
||||||
|
struct device *next_sibling;
|
||||||
|
struct device *sibling;
|
||||||
|
struct device *chip;
|
||||||
|
struct resource *res;
|
||||||
|
struct reg *reg;
|
||||||
|
} *head, *lastdev, *cur_parent, *cur_bus, root;
|
||||||
|
|
||||||
|
struct header;
|
||||||
|
struct header {
|
||||||
|
char *name;
|
||||||
|
struct header *next;
|
||||||
|
} headers;
|
||||||
|
|
||||||
|
int devcount = 0;
|
||||||
|
|
||||||
|
struct device *new_dev() {
|
||||||
|
struct device *dev = malloc(sizeof(struct device));
|
||||||
|
memset(dev, 0, sizeof(struct device));
|
||||||
|
dev->id = ++devcount;
|
||||||
|
dev->parent = cur_parent;
|
||||||
|
dev->bus = cur_bus;
|
||||||
|
head->next = dev;
|
||||||
|
head = dev;
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_match(struct device *a, struct device *b) {
|
||||||
|
if ((a->bustype == b->bustype) && (a->bus == b->bus) && (a->path_a == b->path_a) && (a->path_b == b->path_b))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fold_in(struct device *parent) {
|
||||||
|
struct device *child = parent->children;
|
||||||
|
struct device *latest = 0;
|
||||||
|
while (child != latest) {
|
||||||
|
if (child->children) {
|
||||||
|
if (!latest) latest = child->children;
|
||||||
|
parent->latestchild->next_sibling = child->children;
|
||||||
|
parent->latestchild = child->latestchild;
|
||||||
|
}
|
||||||
|
child = child->next_sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int yywrap(void) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyerror (char const *str)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s\n", str);
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
%union {
|
||||||
|
struct device *device;
|
||||||
|
char *string;
|
||||||
|
int number;
|
||||||
|
}
|
||||||
|
%token CHIP DEVICE REGISTER BOOL BUS RESOURCE END EQUALS HEX STRING PCI PNP I2C APIC APIC_CLUSTER PCI_DOMAIN IRQ DRQ IO NUMBER
|
||||||
|
%%
|
||||||
|
devtree: devchip {
|
||||||
|
root.next_sibling = root.children;
|
||||||
|
root.next_sibling->next_sibling = root.next_sibling->children;
|
||||||
|
|
||||||
|
struct device *dev = &root;
|
||||||
|
while (dev) {
|
||||||
|
/* skip "chip" elements in children chain */
|
||||||
|
while (dev->children && (dev->children->type == chip)) dev->children = dev->children->children;
|
||||||
|
/* skip "chip" elements and functions of the same device in sibling chain */
|
||||||
|
while (dev->sibling && dev->sibling->used) dev->sibling = dev->sibling->sibling;
|
||||||
|
/* If end of chain, and parent is a chip, move on */
|
||||||
|
if (!dev->sibling && (dev->parent->type == chip)) dev->sibling = dev->parent->sibling;
|
||||||
|
/* skip chips */
|
||||||
|
while (dev->sibling && dev->sibling->type == chip) dev->sibling = dev->sibling->children;
|
||||||
|
/* skip duplicate function elements in nextdev chain */
|
||||||
|
while (dev->nextdev && dev->nextdev->used) dev->nextdev = dev->nextdev->nextdev;
|
||||||
|
dev = dev->next_sibling;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
devchip: chip | device ;
|
||||||
|
|
||||||
|
devices: devices devchip | devices registers | ;
|
||||||
|
|
||||||
|
devicesorresources: devicesorresources devchip | devicesorresources resource | ;
|
||||||
|
|
||||||
|
chip: CHIP STRING /* == path */ {
|
||||||
|
$<device>$ = new_dev();
|
||||||
|
$<device>$->chiph_exists = 1;
|
||||||
|
$<device>$->name = $<string>2;
|
||||||
|
$<device>$->name_underscore = strdup($<device>$->name);
|
||||||
|
char *c;
|
||||||
|
for (c = $<device>$->name_underscore; *c; c++) {
|
||||||
|
if (*c == '/') *c = '_';
|
||||||
|
}
|
||||||
|
$<device>$->type = chip;
|
||||||
|
$<device>$->chip = $<device>$;
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
char *chip_h = malloc(strlen($<string>2)+12);
|
||||||
|
sprintf(chip_h, "src/%s/chip.h", $<string>2);
|
||||||
|
if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
|
||||||
|
$<device>$->chiph_exists = 0;
|
||||||
|
|
||||||
|
if (cur_parent->latestchild) {
|
||||||
|
cur_parent->latestchild->next_sibling = $<device>$;
|
||||||
|
cur_parent->latestchild->sibling = $<device>$;
|
||||||
|
}
|
||||||
|
cur_parent->latestchild = $<device>$;
|
||||||
|
if (!cur_parent->children)
|
||||||
|
cur_parent->children = $<device>$;
|
||||||
|
|
||||||
|
cur_parent = $<device>$;
|
||||||
|
}
|
||||||
|
devices END {
|
||||||
|
cur_parent = $<device>3->parent;
|
||||||
|
|
||||||
|
fold_in($<device>3);
|
||||||
|
|
||||||
|
if ($<device>3->chiph_exists) {
|
||||||
|
int include_exists = 0;
|
||||||
|
struct header *h = &headers;
|
||||||
|
while (h->next) {
|
||||||
|
int result = strcmp($<device>3->name, h->next->name);
|
||||||
|
if (result == 0) {
|
||||||
|
include_exists = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (result < 0) break;
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
if (!include_exists) {
|
||||||
|
struct header *tmp = h->next;
|
||||||
|
h->next = malloc(sizeof(struct header));
|
||||||
|
memset(h->next, 0, sizeof(struct header));
|
||||||
|
h->next->name = $<device>3->name;
|
||||||
|
h->next->next = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
device: DEVICE BUS NUMBER /* == devnum */ BOOL {
|
||||||
|
$<device>$ = new_dev();
|
||||||
|
$<device>$->bustype = $<number>2;
|
||||||
|
|
||||||
|
char *tmp;
|
||||||
|
$<device>$->path_a = strtol(strdup($<string>3), &tmp, 16);
|
||||||
|
if (*tmp == '.') {
|
||||||
|
tmp++;
|
||||||
|
$<device>$->path_b = strtol(tmp, NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *name = malloc(10);
|
||||||
|
sprintf(name, "_dev%d", $<device>$->id);
|
||||||
|
$<device>$->name = name;
|
||||||
|
$<device>$->name_underscore = name; // shouldn't be necessary, but avoid 0-ptr
|
||||||
|
$<device>$->type = device;
|
||||||
|
$<device>$->enabled = $<number>4;
|
||||||
|
$<device>$->chip = $<device>$->parent->chip;
|
||||||
|
|
||||||
|
if (cur_parent->latestchild) {
|
||||||
|
cur_parent->latestchild->next_sibling = $<device>$;
|
||||||
|
cur_parent->latestchild->sibling = $<device>$;
|
||||||
|
}
|
||||||
|
cur_parent->latestchild = $<device>$;
|
||||||
|
if (!cur_parent->children)
|
||||||
|
cur_parent->children = $<device>$;
|
||||||
|
|
||||||
|
lastdev->nextdev = $<device>$;
|
||||||
|
lastdev = $<device>$;
|
||||||
|
if ($<number>2 == PCI) {
|
||||||
|
$<device>$->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
|
||||||
|
}
|
||||||
|
if ($<number>2 == PNP) {
|
||||||
|
$<device>$->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
|
||||||
|
}
|
||||||
|
if ($<number>2 == I2C) {
|
||||||
|
$<device>$->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x }}";
|
||||||
|
}
|
||||||
|
if ($<number>2 == APIC) {
|
||||||
|
$<device>$->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
|
||||||
|
}
|
||||||
|
if ($<number>2 == APIC_CLUSTER) {
|
||||||
|
$<device>$->path = ".type=DEVICE_PATH_APIC_CLUSTER,{.apic_cluster={ .cluster = 0x%x }}";
|
||||||
|
}
|
||||||
|
if ($<number>2 == PCI_DOMAIN) {
|
||||||
|
$<device>$->path = ".type=DEVICE_PATH_PCI_DOMAIN,{.pci_domain={ .domain = 0x%x }}";
|
||||||
|
}
|
||||||
|
cur_parent = $<device>$;
|
||||||
|
cur_bus = $<device>$;
|
||||||
|
}
|
||||||
|
devicesorresources END {
|
||||||
|
cur_parent = $<device>5->parent;
|
||||||
|
cur_bus = $<device>5->bus;
|
||||||
|
|
||||||
|
fold_in($<device>5);
|
||||||
|
|
||||||
|
struct device *d = $<device>5->children;
|
||||||
|
while (d) {
|
||||||
|
int link = 0;
|
||||||
|
struct device *cmp = d->next_sibling;
|
||||||
|
while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a) && (cmp->path_b == d->path_b)) {
|
||||||
|
if (cmp->type==device && !cmp->used) {
|
||||||
|
if (device_match(d, cmp)) {
|
||||||
|
d->multidev = 1;
|
||||||
|
|
||||||
|
cmp->aliased_name = malloc(12);
|
||||||
|
sprintf(cmp->aliased_name, "_dev%d", cmp->id);
|
||||||
|
cmp->id = d->id;
|
||||||
|
cmp->name = d->name;
|
||||||
|
cmp->used = 1;
|
||||||
|
cmp->link = ++link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmp = cmp->next_sibling;
|
||||||
|
}
|
||||||
|
d = d->next_sibling;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
resource: RESOURCE NUMBER /* == resnum */ EQUALS NUMBER /* == resval */
|
||||||
|
{
|
||||||
|
struct resource *r = malloc(sizeof(struct resource));
|
||||||
|
memset (r, 0, sizeof(struct resource));
|
||||||
|
r->type = $<number>1;
|
||||||
|
r->index = strtol($<string>2, NULL, 0);
|
||||||
|
r->base = strtol($<string>4, NULL, 0);
|
||||||
|
if (cur_parent->res) {
|
||||||
|
struct resource *head = cur_parent->res;
|
||||||
|
while (head->next) head = head->next;
|
||||||
|
head->next = r;
|
||||||
|
} else {
|
||||||
|
cur_parent->res = r;
|
||||||
|
}
|
||||||
|
cur_parent->rescnt++;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
registers: REGISTER STRING /* == regname */ EQUALS STRING /* == regval */
|
||||||
|
{
|
||||||
|
struct reg *r = malloc(sizeof(struct reg));
|
||||||
|
memset (r, 0, sizeof(struct reg));
|
||||||
|
r->key = $<string>2;
|
||||||
|
r->value = $<string>4;
|
||||||
|
if (cur_parent->reg) {
|
||||||
|
struct reg *head = cur_parent->reg;
|
||||||
|
// sorting to be equal to sconfig's behaviour
|
||||||
|
int sort = strcmp(r->key, head->key);
|
||||||
|
if (sort == 0) {
|
||||||
|
printf("ERROR: duplicate 'register' key.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (sort<0) {
|
||||||
|
r->next = head;
|
||||||
|
cur_parent->reg = r;
|
||||||
|
} else {
|
||||||
|
while ((head->next) && (strcmp(head->next->key, r->key)<0)) head = head->next;
|
||||||
|
r->next = head->next;
|
||||||
|
head->next = r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur_parent->reg = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
void pass0(FILE *fil, struct device *ptr) {
|
||||||
|
if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used))
|
||||||
|
fprintf(fil, "struct device %s;\n", ptr->name);
|
||||||
|
if ((ptr->type == device) && (ptr->id != 0) && ptr->used)
|
||||||
|
fprintf(fil, "struct device %s;\n", ptr->aliased_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass1(FILE *fil, struct device *ptr) {
|
||||||
|
if (!ptr->used && (ptr->type == device)) {
|
||||||
|
fprintf(fil, "struct device %s = {\n", ptr->name);
|
||||||
|
fprintf(fil, "\t.ops = %s,\n", (ptr->ops)?(ptr->ops):"0");
|
||||||
|
fprintf(fil, "\t.bus = &%s.link[%d],\n", ptr->bus->name, ptr->bus->link);
|
||||||
|
fprintf(fil, "\t.path = {");
|
||||||
|
fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
|
||||||
|
fprintf(fil, "},\n");
|
||||||
|
fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
|
||||||
|
fprintf(fil, "\t.on_mainboard = 1,\n");
|
||||||
|
if (ptr->rescnt > 0) {
|
||||||
|
fprintf(fil, "\t.resources = %d,\n", ptr->rescnt);
|
||||||
|
fprintf(fil, "\t.resource = {\n");
|
||||||
|
struct resource *r = ptr->res;
|
||||||
|
while (r) {
|
||||||
|
fprintf(fil, "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
|
||||||
|
if (r->type == IRQ) fprintf(fil, "IRQ");
|
||||||
|
if (r->type == DRQ) fprintf(fil, "DRQ");
|
||||||
|
if (r->type == IO) fprintf(fil, "IO");
|
||||||
|
fprintf(fil, ", .index=0x%x, .base=0x%x},\n", r->index, r->base);
|
||||||
|
r = r->next;
|
||||||
|
}
|
||||||
|
fprintf(fil, "\t },\n");
|
||||||
|
}
|
||||||
|
int link = 0;
|
||||||
|
fprintf(fil, "\t.link = {\n");
|
||||||
|
if (ptr->multidev) {
|
||||||
|
struct device *d = ptr;
|
||||||
|
while (d) {
|
||||||
|
if (device_match(d, ptr)) {
|
||||||
|
fprintf(fil, "\t\t[%d] = {\n", d->link);
|
||||||
|
fprintf(fil, "\t\t\t.link = %d,\n", d->link);
|
||||||
|
fprintf(fil, "\t\t\t.dev = &%s,\n", d->name);
|
||||||
|
if (d->children)
|
||||||
|
fprintf(fil, "\t\t\t.children = &%s,\n", d->children->name);
|
||||||
|
fprintf(fil, "\t\t},\n");
|
||||||
|
link++;
|
||||||
|
}
|
||||||
|
d = d->next_sibling;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ptr->children) {
|
||||||
|
fprintf(fil, "\t\t[0] = {\n");
|
||||||
|
fprintf(fil, "\t\t\t.link = 0,\n");
|
||||||
|
fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
|
||||||
|
fprintf(fil, "\t\t\t.children = &%s,\n", ptr->children->name);
|
||||||
|
fprintf(fil, "\t\t},\n");
|
||||||
|
link++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(fil, "\t},\n");
|
||||||
|
fprintf(fil, "\t.links = %d,\n", link);
|
||||||
|
if (ptr->sibling)
|
||||||
|
fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
|
||||||
|
if (ptr->chip->chiph_exists) {
|
||||||
|
fprintf(fil, "\t.chip_ops = &%s_ops,\n", ptr->chip->name_underscore);
|
||||||
|
fprintf(fil, "\t.chip_info = &%s_info_%d,\n", ptr->chip->name_underscore, ptr->chip->id);
|
||||||
|
}
|
||||||
|
if (ptr->nextdev)
|
||||||
|
fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
|
||||||
|
fprintf(fil, "};\n");
|
||||||
|
}
|
||||||
|
if ((ptr->type == chip) && (ptr->chiph_exists)) {
|
||||||
|
if (ptr->reg) {
|
||||||
|
fprintf(fil, "struct %s_config %s_info_%d\t= {\n", ptr->name_underscore, ptr->name_underscore, ptr->id);
|
||||||
|
struct reg *r = ptr->reg;
|
||||||
|
while (r) {
|
||||||
|
fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
|
||||||
|
r = r->next;
|
||||||
|
}
|
||||||
|
fprintf(fil, "};\n\n");
|
||||||
|
} else {
|
||||||
|
fprintf(fil, "struct %s_config %s_info_%d;\n", ptr->name_underscore, ptr->name_underscore, ptr->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void walk_device_tree(FILE *fil, struct device *ptr, void (*func)(FILE *, struct device*), struct device *chips) {
|
||||||
|
do {
|
||||||
|
func(fil, ptr);
|
||||||
|
ptr = ptr->next_sibling;
|
||||||
|
} while (ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct device mainboard = {
|
||||||
|
.name = "mainboard",
|
||||||
|
.name_underscore = "mainboard",
|
||||||
|
.id = 0,
|
||||||
|
.chip = &mainboard,
|
||||||
|
.type = chip,
|
||||||
|
.chiph_exists = 1,
|
||||||
|
.children = &root
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device root = {
|
||||||
|
.name = "dev_root",
|
||||||
|
.name_underscore = "dev_root",
|
||||||
|
.id = 0,
|
||||||
|
.chip = &mainboard,
|
||||||
|
.type = device,
|
||||||
|
.path = " .type = DEVICE_PATH_ROOT ",
|
||||||
|
.ops = "&default_dev_ops_root",
|
||||||
|
.parent = &root,
|
||||||
|
.bus = &root,
|
||||||
|
.enabled = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("usage: sconfig vendor/mainboard outputdir\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char *mainboard=argv[1];
|
||||||
|
char *outputdir=argv[2];
|
||||||
|
char *devtree=malloc(strlen(mainboard)+30);
|
||||||
|
char *outputc=malloc(strlen(outputdir)+10);
|
||||||
|
sprintf(devtree, "src/mainboard/%s/devicetree.cb", mainboard);
|
||||||
|
sprintf(outputc, "%s/static.c", outputdir);
|
||||||
|
|
||||||
|
headers.next = malloc(sizeof(struct header));
|
||||||
|
headers.next->name = malloc(strlen(mainboard)+12);
|
||||||
|
headers.next->next = 0;
|
||||||
|
sprintf(headers.next->name, "mainboard/%s", mainboard);
|
||||||
|
|
||||||
|
FILE *filec = fopen(devtree, "r");
|
||||||
|
yyrestart(filec);
|
||||||
|
|
||||||
|
FILE *staticc = fopen(outputc, "w");
|
||||||
|
|
||||||
|
cur_bus = cur_parent = lastdev = head = &root;
|
||||||
|
yyparse();
|
||||||
|
fclose(filec);
|
||||||
|
|
||||||
|
if ((head->type == chip) && (!head->chiph_exists)) {
|
||||||
|
struct device *tmp = head;
|
||||||
|
head = &root;
|
||||||
|
while (head->next != tmp) head = head->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(staticc, "#include <device/device.h>\n");
|
||||||
|
fprintf(staticc, "#include <device/pci.h>\n");
|
||||||
|
struct header *h = &headers;
|
||||||
|
while (h->next) {
|
||||||
|
h = h->next;
|
||||||
|
fprintf(staticc, "#include \"%s/chip.h\"\n", h->name);
|
||||||
|
}
|
||||||
|
fprintf(staticc, "\n/* pass 0 */\n");
|
||||||
|
walk_device_tree(staticc, &root, pass0, NULL);
|
||||||
|
fprintf(staticc, "\n/* pass 1 */\nstruct mainboard_config mainboard_info_0;\nstruct device **last_dev_p = &%s.next;\n", lastdev->name);
|
||||||
|
walk_device_tree(staticc, &root, pass1, NULL);
|
||||||
|
|
||||||
|
fclose(staticc);
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
target x
|
|
||||||
mainboard amd/solo
|
|
||||||
# option X=1
|
|
||||||
# makerule x y "z"
|
|
||||||
payload /dev/null
|
|
||||||
end
|
|
|
@ -1,779 +0,0 @@
|
||||||
# Yapps 2.0 - yet another python parser system
|
|
||||||
# Amit J Patel, January 1999
|
|
||||||
# See http://theory.stanford.edu/~amitp/Yapps/ for documentation and updates
|
|
||||||
|
|
||||||
# v2.0.1 changes (October 2001):
|
|
||||||
# * The exceptions inherit the standard Exception class (thanks Rich Salz)
|
|
||||||
# * The scanner can use either a different set of regular expressions
|
|
||||||
# per instance, or allows the subclass to define class fields with
|
|
||||||
# the patterns. This improves performance when many Scanner objects
|
|
||||||
# are being created, because the regular expressions don't have to
|
|
||||||
# be recompiled each time. (thanks Amaury Forgeot d'Arc)
|
|
||||||
# v2.0.2 changes (April 2002)
|
|
||||||
# * Fixed a bug in generating the 'else' clause when the comment was too
|
|
||||||
# long. v2.0.1 was missing a newline. (thanks Steven Engelhardt)
|
|
||||||
# v2.0.3 changes (August 2002)
|
|
||||||
# * Fixed a bug with inline tokens using the r"" syntax.
|
|
||||||
|
|
||||||
from string import *
|
|
||||||
from yappsrt import *
|
|
||||||
import re
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
INDENT = " "*4
|
|
||||||
|
|
||||||
class Generator:
|
|
||||||
def __init__(self, name, options, tokens, rules):
|
|
||||||
self.change_count = 0
|
|
||||||
self.name = name
|
|
||||||
self.options = options
|
|
||||||
self.preparser = ''
|
|
||||||
self.postparser = None
|
|
||||||
|
|
||||||
self.tokens = {} # Map from tokens to regexps
|
|
||||||
self.ignore = [] # List of token names to ignore in parsing
|
|
||||||
self.terminals = [] # List of token names (to maintain ordering)
|
|
||||||
for n,t in tokens:
|
|
||||||
if n == '#ignore':
|
|
||||||
n = t
|
|
||||||
self.ignore.append(n)
|
|
||||||
if n in self.tokens.keys() and self.tokens[n] != t:
|
|
||||||
print 'Warning: token', n, 'multiply defined.'
|
|
||||||
self.tokens[n] = t
|
|
||||||
self.terminals.append(n)
|
|
||||||
|
|
||||||
self.rules = {} # Map from rule names to parser nodes
|
|
||||||
self.params = {} # Map from rule names to parameters
|
|
||||||
self.goals = [] # List of rule names (to maintain ordering)
|
|
||||||
for n,p,r in rules:
|
|
||||||
self.params[n] = p
|
|
||||||
self.rules[n] = r
|
|
||||||
self.goals.append(n)
|
|
||||||
|
|
||||||
import sys
|
|
||||||
self.output = sys.stdout
|
|
||||||
|
|
||||||
def __getitem__(self, name):
|
|
||||||
# Get options
|
|
||||||
return self.options.get(name, 0)
|
|
||||||
|
|
||||||
def non_ignored_tokens(self):
|
|
||||||
return filter(lambda x, i=self.ignore: x not in i, self.terminals)
|
|
||||||
|
|
||||||
def changed(self):
|
|
||||||
self.change_count = 1+self.change_count
|
|
||||||
|
|
||||||
def subset(self, a, b):
|
|
||||||
"See if all elements of a are inside b"
|
|
||||||
for x in a:
|
|
||||||
if x not in b: return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
def equal_set(self, a, b):
|
|
||||||
"See if a and b have the same elements"
|
|
||||||
if len(a) != len(b): return 0
|
|
||||||
if a == b: return 1
|
|
||||||
return self.subset(a, b) and self.subset(b, a)
|
|
||||||
|
|
||||||
def add_to(self, parent, additions):
|
|
||||||
"Modify parent to include all elements in additions"
|
|
||||||
for x in additions:
|
|
||||||
if x not in parent:
|
|
||||||
parent.append(x)
|
|
||||||
self.changed()
|
|
||||||
|
|
||||||
def equate(self, a, b):
|
|
||||||
self.add_to(a, b)
|
|
||||||
self.add_to(b, a)
|
|
||||||
|
|
||||||
def write(self, *args):
|
|
||||||
for a in args:
|
|
||||||
self.output.write(a)
|
|
||||||
|
|
||||||
def in_test(self, x, full, b):
|
|
||||||
if not b: return '0'
|
|
||||||
if len(b)==1: return '%s == %s' % (x, `b[0]`)
|
|
||||||
if full and len(b) > len(full)/2:
|
|
||||||
# Reverse the sense of the test.
|
|
||||||
not_b = filter(lambda x, b=b: x not in b, full)
|
|
||||||
return self.not_in_test(x, full, not_b)
|
|
||||||
return '%s in %s' % (x, `b`)
|
|
||||||
|
|
||||||
def not_in_test(self, x, full, b):
|
|
||||||
if not b: return '1'
|
|
||||||
if len(b)==1: return '%s != %s' % (x, `b[0]`)
|
|
||||||
return '%s not in %s' % (x, `b`)
|
|
||||||
|
|
||||||
def peek_call(self, a):
|
|
||||||
a_set = (`a`[1:-1])
|
|
||||||
if self.equal_set(a, self.non_ignored_tokens()): a_set = ''
|
|
||||||
if self['context-insensitive-scanner']: a_set = ''
|
|
||||||
return 'self._peek(%s)' % a_set
|
|
||||||
|
|
||||||
def peek_test(self, a, b):
|
|
||||||
if self.subset(a, b): return '1'
|
|
||||||
if self['context-insensitive-scanner']: a = self.non_ignored_tokens()
|
|
||||||
return self.in_test(self.peek_call(a), a, b)
|
|
||||||
|
|
||||||
def not_peek_test(self, a, b):
|
|
||||||
if self.subset(a, b): return '0'
|
|
||||||
return self.not_in_test(self.peek_call(a), a, b)
|
|
||||||
|
|
||||||
def calculate(self):
|
|
||||||
while 1:
|
|
||||||
for r in self.goals:
|
|
||||||
self.rules[r].setup(self, r)
|
|
||||||
if self.change_count == 0: break
|
|
||||||
self.change_count = 0
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
for r in self.goals:
|
|
||||||
self.rules[r].update(self)
|
|
||||||
if self.change_count == 0: break
|
|
||||||
self.change_count = 0
|
|
||||||
|
|
||||||
def dump_information(self):
|
|
||||||
self.calculate()
|
|
||||||
for r in self.goals:
|
|
||||||
print ' _____' + '_'*len(r)
|
|
||||||
print ('___/Rule '+r+'\\' + '_'*80)[:79]
|
|
||||||
queue = [self.rules[r]]
|
|
||||||
while queue:
|
|
||||||
top = queue[0]
|
|
||||||
del queue[0]
|
|
||||||
|
|
||||||
print `top`
|
|
||||||
top.first.sort()
|
|
||||||
top.follow.sort()
|
|
||||||
eps = []
|
|
||||||
if top.accepts_epsilon: eps = ['(null)']
|
|
||||||
print ' FIRST:', join(top.first+eps, ', ')
|
|
||||||
print ' FOLLOW:', join(top.follow, ', ')
|
|
||||||
for x in top.get_children(): queue.append(x)
|
|
||||||
|
|
||||||
def generate_output(self):
|
|
||||||
self.calculate()
|
|
||||||
self.write(self.preparser)
|
|
||||||
self.write("from string import *\n")
|
|
||||||
self.write("import re\n")
|
|
||||||
self.write("from yappsrt import *\n")
|
|
||||||
self.write("\n")
|
|
||||||
self.write("class ", self.name, "Scanner(Scanner):\n")
|
|
||||||
self.write(" patterns = [\n")
|
|
||||||
for p in self.terminals:
|
|
||||||
self.write(" (%s, re.compile(%s)),\n" % (
|
|
||||||
`p`, `self.tokens[p]`))
|
|
||||||
self.write(" ]\n")
|
|
||||||
self.write(" def __init__(self, str):\n")
|
|
||||||
self.write(" Scanner.__init__(self,None,%s,str)\n" %
|
|
||||||
`self.ignore`)
|
|
||||||
self.write("\n")
|
|
||||||
|
|
||||||
self.write("class ", self.name, "(Parser):\n")
|
|
||||||
for r in self.goals:
|
|
||||||
self.write(INDENT, "def ", r, "(self")
|
|
||||||
if self.params[r]: self.write(", ", self.params[r])
|
|
||||||
self.write("):\n")
|
|
||||||
self.rules[r].output(self, INDENT+INDENT)
|
|
||||||
self.write("\n")
|
|
||||||
|
|
||||||
self.write("\n")
|
|
||||||
self.write("def parse(rule, text):\n")
|
|
||||||
self.write(" P = ", self.name, "(", self.name, "Scanner(text))\n")
|
|
||||||
self.write(" return wrap_error_reporter(P, rule)\n")
|
|
||||||
self.write("\n")
|
|
||||||
if self.postparser is not None:
|
|
||||||
self.write(self.postparser)
|
|
||||||
else:
|
|
||||||
self.write("if __name__=='__main__':\n")
|
|
||||||
self.write(INDENT, "from sys import argv, stdin\n")
|
|
||||||
self.write(INDENT, "if len(argv) >= 2:\n")
|
|
||||||
self.write(INDENT*2, "if len(argv) >= 3:\n")
|
|
||||||
self.write(INDENT*3, "f = open(argv[2],'r')\n")
|
|
||||||
self.write(INDENT*2, "else:\n")
|
|
||||||
self.write(INDENT*3, "f = stdin\n")
|
|
||||||
self.write(INDENT*2, "print parse(argv[1], f.read())\n")
|
|
||||||
self.write(INDENT, "else: print 'Args: <rule> [<filename>]'\n")
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
class Node:
|
|
||||||
def __init__(self):
|
|
||||||
self.first = []
|
|
||||||
self.follow = []
|
|
||||||
self.accepts_epsilon = 0
|
|
||||||
self.rule = '?'
|
|
||||||
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
# Setup will change accepts_epsilon,
|
|
||||||
# sometimes from 0 to 1 but never 1 to 0.
|
|
||||||
# It will take a finite number of steps to set things up
|
|
||||||
self.rule = rule
|
|
||||||
|
|
||||||
def used(self, vars):
|
|
||||||
"Return two lists: one of vars used, and the other of vars assigned"
|
|
||||||
return vars, []
|
|
||||||
|
|
||||||
def get_children(self):
|
|
||||||
"Return a list of sub-nodes"
|
|
||||||
return []
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
if self.accepts_epsilon:
|
|
||||||
gen.add_to(self.first, self.follow)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
"Write out code to _gen_ with _indent_:string indentation"
|
|
||||||
gen.write(indent, "assert 0 # Invalid parser node\n")
|
|
||||||
|
|
||||||
class Terminal(Node):
|
|
||||||
def __init__(self, token):
|
|
||||||
Node.__init__(self)
|
|
||||||
self.token = token
|
|
||||||
self.accepts_epsilon = 0
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.token
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
Node.update(self, gen)
|
|
||||||
if self.first != [self.token]:
|
|
||||||
self.first = [self.token]
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
gen.write(indent)
|
|
||||||
if re.match('[a-zA-Z_]+$', self.token):
|
|
||||||
gen.write(self.token, " = ")
|
|
||||||
gen.write("self._scan(%s)\n" % `self.token`)
|
|
||||||
|
|
||||||
class Eval(Node):
|
|
||||||
def __init__(self, expr):
|
|
||||||
Node.__init__(self)
|
|
||||||
self.expr = expr
|
|
||||||
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Node.setup(self, gen, rule)
|
|
||||||
if not self.accepts_epsilon:
|
|
||||||
self.accepts_epsilon = 1
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '{{ %s }}' % strip(self.expr)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
gen.write(indent, strip(self.expr), '\n')
|
|
||||||
|
|
||||||
class NonTerminal(Node):
|
|
||||||
def __init__(self, name, args):
|
|
||||||
Node.__init__(self)
|
|
||||||
self.name = name
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Node.setup(self, gen, rule)
|
|
||||||
try:
|
|
||||||
self.target = gen.rules[self.name]
|
|
||||||
if self.accepts_epsilon != self.target.accepts_epsilon:
|
|
||||||
self.accepts_epsilon = self.target.accepts_epsilon
|
|
||||||
gen.changed()
|
|
||||||
except KeyError: # Oops, it's nonexistent
|
|
||||||
print 'Error: no rule <%s>' % self.name
|
|
||||||
self.target = self
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '<%s>' % self.name
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
Node.update(self, gen)
|
|
||||||
gen.equate(self.first, self.target.first)
|
|
||||||
gen.equate(self.follow, self.target.follow)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
gen.write(indent)
|
|
||||||
gen.write(self.name, " = ")
|
|
||||||
gen.write("self.", self.name, "(", self.args, ")\n")
|
|
||||||
|
|
||||||
class Sequence(Node):
|
|
||||||
def __init__(self, *children):
|
|
||||||
Node.__init__(self)
|
|
||||||
self.children = children
|
|
||||||
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Node.setup(self, gen, rule)
|
|
||||||
for c in self.children: c.setup(gen, rule)
|
|
||||||
|
|
||||||
if not self.accepts_epsilon:
|
|
||||||
# If it's not already accepting epsilon, it might now do so.
|
|
||||||
for c in self.children:
|
|
||||||
# any non-epsilon means all is non-epsilon
|
|
||||||
if not c.accepts_epsilon: break
|
|
||||||
else:
|
|
||||||
self.accepts_epsilon = 1
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def get_children(self):
|
|
||||||
return self.children
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '( %s )' % join(map(lambda x: str(x), self.children))
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
Node.update(self, gen)
|
|
||||||
for g in self.children:
|
|
||||||
g.update(gen)
|
|
||||||
|
|
||||||
empty = 1
|
|
||||||
for g_i in range(len(self.children)):
|
|
||||||
g = self.children[g_i]
|
|
||||||
|
|
||||||
if empty: gen.add_to(self.first, g.first)
|
|
||||||
if not g.accepts_epsilon: empty = 0
|
|
||||||
|
|
||||||
if g_i == len(self.children)-1:
|
|
||||||
next = self.follow
|
|
||||||
else:
|
|
||||||
next = self.children[1+g_i].first
|
|
||||||
gen.add_to(g.follow, next)
|
|
||||||
|
|
||||||
if self.children:
|
|
||||||
gen.add_to(self.follow, self.children[-1].follow)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
if self.children:
|
|
||||||
for c in self.children:
|
|
||||||
c.output(gen, indent)
|
|
||||||
else:
|
|
||||||
# Placeholder for empty sequences, just in case
|
|
||||||
gen.write(indent, 'pass\n')
|
|
||||||
|
|
||||||
class Choice(Node):
|
|
||||||
def __init__(self, *children):
|
|
||||||
Node.__init__(self)
|
|
||||||
self.children = children
|
|
||||||
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Node.setup(self, gen, rule)
|
|
||||||
for c in self.children: c.setup(gen, rule)
|
|
||||||
|
|
||||||
if not self.accepts_epsilon:
|
|
||||||
for c in self.children:
|
|
||||||
if c.accepts_epsilon:
|
|
||||||
self.accepts_epsilon = 1
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def get_children(self):
|
|
||||||
return self.children
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '( %s )' % join(map(lambda x: str(x), self.children), ' | ')
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
Node.update(self, gen)
|
|
||||||
for g in self.children:
|
|
||||||
g.update(gen)
|
|
||||||
|
|
||||||
for g in self.children:
|
|
||||||
gen.add_to(self.first, g.first)
|
|
||||||
gen.add_to(self.follow, g.follow)
|
|
||||||
for g in self.children:
|
|
||||||
gen.add_to(g.follow, self.follow)
|
|
||||||
if self.accepts_epsilon:
|
|
||||||
gen.add_to(self.first, self.follow)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
test = "if"
|
|
||||||
gen.write(indent, "_token_ = ", gen.peek_call(self.first), "\n")
|
|
||||||
tokens_seen = []
|
|
||||||
tokens_unseen = self.first[:]
|
|
||||||
if gen['context-insensitive-scanner']:
|
|
||||||
# Context insensitive scanners can return ANY token,
|
|
||||||
# not only the ones in first.
|
|
||||||
tokens_unseen = gen.non_ignored_tokens()
|
|
||||||
for c in self.children:
|
|
||||||
testset = c.first[:]
|
|
||||||
removed = []
|
|
||||||
for x in testset:
|
|
||||||
if x in tokens_seen:
|
|
||||||
testset.remove(x)
|
|
||||||
removed.append(x)
|
|
||||||
if x in tokens_unseen: tokens_unseen.remove(x)
|
|
||||||
tokens_seen = tokens_seen + testset
|
|
||||||
if removed:
|
|
||||||
if not testset:
|
|
||||||
print 'Error in rule', self.rule+':', c, 'never matches.'
|
|
||||||
else:
|
|
||||||
print 'Warning:', self
|
|
||||||
print ' * These tokens are being ignored:', join(removed, ', ')
|
|
||||||
print ' due to previous choices using them.'
|
|
||||||
|
|
||||||
if testset:
|
|
||||||
if not tokens_unseen: # context sensitive scanners only!
|
|
||||||
if test=='if':
|
|
||||||
# if it's the first AND last test, then
|
|
||||||
# we can simply put the code without an if/else
|
|
||||||
c.output(gen, indent)
|
|
||||||
else:
|
|
||||||
gen.write(indent, "else: ")
|
|
||||||
t = gen.in_test('', [], testset)
|
|
||||||
if len(t) < 70-len(indent):
|
|
||||||
gen.write("#", t)
|
|
||||||
gen.write("\n")
|
|
||||||
c.output(gen, indent+INDENT)
|
|
||||||
else:
|
|
||||||
gen.write(indent, test, " ",
|
|
||||||
gen.in_test('_token_', tokens_unseen, testset),
|
|
||||||
":\n")
|
|
||||||
c.output(gen, indent+INDENT)
|
|
||||||
test = "elif"
|
|
||||||
|
|
||||||
if gen['context-insensitive-scanner'] and tokens_unseen:
|
|
||||||
gen.write(indent, "else:\n")
|
|
||||||
gen.write(indent, INDENT, "raise SyntaxError(self._pos, ")
|
|
||||||
gen.write("'Could not match ", self.rule, "')\n")
|
|
||||||
|
|
||||||
class Wrapper(Node):
|
|
||||||
def __init__(self, child):
|
|
||||||
Node.__init__(self)
|
|
||||||
self.child = child
|
|
||||||
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Node.setup(self, gen, rule)
|
|
||||||
self.child.setup(gen, rule)
|
|
||||||
|
|
||||||
def get_children(self):
|
|
||||||
return [self.child]
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
Node.update(self, gen)
|
|
||||||
self.child.update(gen)
|
|
||||||
gen.add_to(self.first, self.child.first)
|
|
||||||
gen.equate(self.follow, self.child.follow)
|
|
||||||
|
|
||||||
class Option(Wrapper):
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Wrapper.setup(self, gen, rule)
|
|
||||||
if not self.accepts_epsilon:
|
|
||||||
self.accepts_epsilon = 1
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '[ %s ]' % str(self.child)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
if self.child.accepts_epsilon:
|
|
||||||
print 'Warning in rule', self.rule+': contents may be empty.'
|
|
||||||
gen.write(indent, "if %s:\n" %
|
|
||||||
gen.peek_test(self.first, self.child.first))
|
|
||||||
self.child.output(gen, indent+INDENT)
|
|
||||||
|
|
||||||
class Plus(Wrapper):
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Wrapper.setup(self, gen, rule)
|
|
||||||
if self.accepts_epsilon != self.child.accepts_epsilon:
|
|
||||||
self.accepts_epsilon = self.child.accepts_epsilon
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '%s+' % str(self.child)
|
|
||||||
|
|
||||||
def update(self, gen):
|
|
||||||
Wrapper.update(self, gen)
|
|
||||||
gen.add_to(self.follow, self.first)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
if self.child.accepts_epsilon:
|
|
||||||
print 'Warning in rule', self.rule+':'
|
|
||||||
print ' * The repeated pattern could be empty. The resulting'
|
|
||||||
print ' parser may not work properly.'
|
|
||||||
gen.write(indent, "while 1:\n")
|
|
||||||
self.child.output(gen, indent+INDENT)
|
|
||||||
union = self.first[:]
|
|
||||||
gen.add_to(union, self.follow)
|
|
||||||
gen.write(indent+INDENT, "if %s: break\n" %
|
|
||||||
gen.not_peek_test(union, self.child.first))
|
|
||||||
|
|
||||||
class Star(Plus):
|
|
||||||
def setup(self, gen, rule):
|
|
||||||
Wrapper.setup(self, gen, rule)
|
|
||||||
if not self.accepts_epsilon:
|
|
||||||
self.accepts_epsilon = 1
|
|
||||||
gen.changed()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '%s*' % str(self.child)
|
|
||||||
|
|
||||||
def output(self, gen, indent):
|
|
||||||
if self.child.accepts_epsilon:
|
|
||||||
print 'Warning in rule', self.rule+':'
|
|
||||||
print ' * The repeated pattern could be empty. The resulting'
|
|
||||||
print ' parser probably will not work properly.'
|
|
||||||
gen.write(indent, "while %s:\n" %
|
|
||||||
gen.peek_test(self.follow, self.child.first))
|
|
||||||
self.child.output(gen, indent+INDENT)
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# The remainder of this file is from parsedesc.{g,py}
|
|
||||||
|
|
||||||
def append(lst, x):
|
|
||||||
"Imperative append"
|
|
||||||
lst.append(x)
|
|
||||||
return lst
|
|
||||||
|
|
||||||
def add_inline_token(tokens, str):
|
|
||||||
tokens.insert( 0, (str, eval(str, {}, {})) )
|
|
||||||
return Terminal(str)
|
|
||||||
|
|
||||||
def cleanup_choice(lst):
|
|
||||||
if len(lst) == 0: return Sequence([])
|
|
||||||
if len(lst) == 1: return lst[0]
|
|
||||||
return apply(Choice, tuple(lst))
|
|
||||||
|
|
||||||
def cleanup_sequence(lst):
|
|
||||||
if len(lst) == 1: return lst[0]
|
|
||||||
return apply(Sequence, tuple(lst))
|
|
||||||
|
|
||||||
def cleanup_rep(node, rep):
|
|
||||||
if rep == 'star': return Star(node)
|
|
||||||
elif rep == 'plus': return Plus(node)
|
|
||||||
else: return node
|
|
||||||
|
|
||||||
def resolve_name(tokens, id, args):
|
|
||||||
if id in map(lambda x: x[0], tokens):
|
|
||||||
# It's a token
|
|
||||||
if args:
|
|
||||||
print 'Warning: ignoring parameters on TOKEN %s<<%s>>' % (id, args)
|
|
||||||
return Terminal(id)
|
|
||||||
else:
|
|
||||||
# It's a name, so assume it's a nonterminal
|
|
||||||
return NonTerminal(id, args)
|
|
||||||
|
|
||||||
|
|
||||||
from string import *
|
|
||||||
import re
|
|
||||||
from yappsrt import *
|
|
||||||
|
|
||||||
class ParserDescriptionScanner(Scanner):
|
|
||||||
def __init__(self, str):
|
|
||||||
Scanner.__init__(self,[
|
|
||||||
('"rule"', 'rule'),
|
|
||||||
('"ignore"', 'ignore'),
|
|
||||||
('"token"', 'token'),
|
|
||||||
('"option"', 'option'),
|
|
||||||
('":"', ':'),
|
|
||||||
('"parser"', 'parser'),
|
|
||||||
('[ \011\015\012]+', '[ \011\015\012]+'),
|
|
||||||
('#.*?\015?\012', '#.*?\015?\012'),
|
|
||||||
('END', '$'),
|
|
||||||
('ATTR', '<<.+?>>'),
|
|
||||||
('STMT', '{{.+?}}'),
|
|
||||||
('ID', '[a-zA-Z_][a-zA-Z_0-9]*'),
|
|
||||||
('STR', '[rR]?\'([^\\n\'\\\\]|\\\\.)*\'|[rR]?"([^\\n"\\\\]|\\\\.)*"'),
|
|
||||||
('LP', '\\('),
|
|
||||||
('RP', '\\)'),
|
|
||||||
('LB', '\\['),
|
|
||||||
('RB', '\\]'),
|
|
||||||
('OR', '[|]'),
|
|
||||||
('STAR', '[*]'),
|
|
||||||
('PLUS', '[+]'),
|
|
||||||
], ['[ \011\015\012]+', '#.*?\015?\012'], str)
|
|
||||||
|
|
||||||
class ParserDescription(Parser):
|
|
||||||
def Parser(self):
|
|
||||||
self._scan('"parser"')
|
|
||||||
ID = self._scan('ID')
|
|
||||||
self._scan('":"')
|
|
||||||
Options = self.Options()
|
|
||||||
Tokens = self.Tokens()
|
|
||||||
Rules = self.Rules(Tokens)
|
|
||||||
END = self._scan('END')
|
|
||||||
return Generator(ID,Options,Tokens,Rules)
|
|
||||||
|
|
||||||
def Options(self):
|
|
||||||
opt = {}
|
|
||||||
while self._peek('"option"', '"token"', '"ignore"', 'END', '"rule"') == '"option"':
|
|
||||||
self._scan('"option"')
|
|
||||||
self._scan('":"')
|
|
||||||
Str = self.Str()
|
|
||||||
opt[Str] = 1
|
|
||||||
return opt
|
|
||||||
|
|
||||||
def Tokens(self):
|
|
||||||
tok = []
|
|
||||||
while self._peek('"token"', '"ignore"', 'END', '"rule"') in ['"token"', '"ignore"']:
|
|
||||||
_token_ = self._peek('"token"', '"ignore"')
|
|
||||||
if _token_ == '"token"':
|
|
||||||
self._scan('"token"')
|
|
||||||
ID = self._scan('ID')
|
|
||||||
self._scan('":"')
|
|
||||||
Str = self.Str()
|
|
||||||
tok.append( (ID,Str) )
|
|
||||||
else: # == '"ignore"'
|
|
||||||
self._scan('"ignore"')
|
|
||||||
self._scan('":"')
|
|
||||||
Str = self.Str()
|
|
||||||
tok.append( ('#ignore',Str) )
|
|
||||||
return tok
|
|
||||||
|
|
||||||
def Rules(self, tokens):
|
|
||||||
rul = []
|
|
||||||
while self._peek('"rule"', 'END') == '"rule"':
|
|
||||||
self._scan('"rule"')
|
|
||||||
ID = self._scan('ID')
|
|
||||||
OptParam = self.OptParam()
|
|
||||||
self._scan('":"')
|
|
||||||
ClauseA = self.ClauseA(tokens)
|
|
||||||
rul.append( (ID,OptParam,ClauseA) )
|
|
||||||
return rul
|
|
||||||
|
|
||||||
def ClauseA(self, tokens):
|
|
||||||
ClauseB = self.ClauseB(tokens)
|
|
||||||
v = [ClauseB]
|
|
||||||
while self._peek('OR', 'RP', 'RB', '"rule"', 'END') == 'OR':
|
|
||||||
OR = self._scan('OR')
|
|
||||||
ClauseB = self.ClauseB(tokens)
|
|
||||||
v.append(ClauseB)
|
|
||||||
return cleanup_choice(v)
|
|
||||||
|
|
||||||
def ClauseB(self, tokens):
|
|
||||||
v = []
|
|
||||||
while self._peek('STR', 'ID', 'LP', 'LB', 'STMT', 'OR', 'RP', 'RB', '"rule"', 'END') in ['STR', 'ID', 'LP', 'LB', 'STMT']:
|
|
||||||
ClauseC = self.ClauseC(tokens)
|
|
||||||
v.append(ClauseC)
|
|
||||||
return cleanup_sequence(v)
|
|
||||||
|
|
||||||
def ClauseC(self, tokens):
|
|
||||||
ClauseD = self.ClauseD(tokens)
|
|
||||||
_token_ = self._peek('PLUS', 'STAR', 'STR', 'ID', 'LP', 'LB', 'STMT', 'OR', 'RP', 'RB', '"rule"', 'END')
|
|
||||||
if _token_ == 'PLUS':
|
|
||||||
PLUS = self._scan('PLUS')
|
|
||||||
return Plus(ClauseD)
|
|
||||||
elif _token_ == 'STAR':
|
|
||||||
STAR = self._scan('STAR')
|
|
||||||
return Star(ClauseD)
|
|
||||||
else:
|
|
||||||
return ClauseD
|
|
||||||
|
|
||||||
def ClauseD(self, tokens):
|
|
||||||
_token_ = self._peek('STR', 'ID', 'LP', 'LB', 'STMT')
|
|
||||||
if _token_ == 'STR':
|
|
||||||
STR = self._scan('STR')
|
|
||||||
t = (STR, eval(STR,{},{}))
|
|
||||||
if t not in tokens: tokens.insert( 0, t )
|
|
||||||
return Terminal(STR)
|
|
||||||
elif _token_ == 'ID':
|
|
||||||
ID = self._scan('ID')
|
|
||||||
OptParam = self.OptParam()
|
|
||||||
return resolve_name(tokens, ID, OptParam)
|
|
||||||
elif _token_ == 'LP':
|
|
||||||
LP = self._scan('LP')
|
|
||||||
ClauseA = self.ClauseA(tokens)
|
|
||||||
RP = self._scan('RP')
|
|
||||||
return ClauseA
|
|
||||||
elif _token_ == 'LB':
|
|
||||||
LB = self._scan('LB')
|
|
||||||
ClauseA = self.ClauseA(tokens)
|
|
||||||
RB = self._scan('RB')
|
|
||||||
return Option(ClauseA)
|
|
||||||
else: # == 'STMT'
|
|
||||||
STMT = self._scan('STMT')
|
|
||||||
return Eval(STMT[2:-2])
|
|
||||||
|
|
||||||
def OptParam(self):
|
|
||||||
if self._peek('ATTR', '":"', 'PLUS', 'STAR', 'STR', 'ID', 'LP', 'LB', 'STMT', 'OR', 'RP', 'RB', '"rule"', 'END') == 'ATTR':
|
|
||||||
ATTR = self._scan('ATTR')
|
|
||||||
return ATTR[2:-2]
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def Str(self):
|
|
||||||
STR = self._scan('STR')
|
|
||||||
return eval(STR,{},{})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# This replaces the default main routine
|
|
||||||
|
|
||||||
yapps_options = [
|
|
||||||
('context-insensitive-scanner', 'context-insensitive-scanner',
|
|
||||||
'Scan all tokens (see docs)')
|
|
||||||
]
|
|
||||||
|
|
||||||
def generate(inputfilename, outputfilename='', dump=0, **flags):
|
|
||||||
"""Generate a grammar, given an input filename (X.g)
|
|
||||||
and an output filename (defaulting to X.py)."""
|
|
||||||
|
|
||||||
if not outputfilename:
|
|
||||||
if inputfilename[-2:]=='.g': outputfilename = inputfilename[:-2]+'.py'
|
|
||||||
else: raise "Invalid Filename", outputfilename
|
|
||||||
|
|
||||||
print ' SCONFIG ', join(outputfilename.split('/')[-4:], '/')
|
|
||||||
|
|
||||||
DIVIDER = '\n%%\n' # This pattern separates the pre/post parsers
|
|
||||||
preparser, postparser = None, None # Code before and after the parser desc
|
|
||||||
|
|
||||||
# Read the entire file
|
|
||||||
s = open(inputfilename,'r').read()
|
|
||||||
|
|
||||||
# See if there's a separation between the pre-parser and parser
|
|
||||||
f = find(s, DIVIDER)
|
|
||||||
if f >= 0: preparser, s = s[:f]+'\n\n', s[f+len(DIVIDER):]
|
|
||||||
|
|
||||||
# See if there's a separation between the parser and post-parser
|
|
||||||
f = find(s, DIVIDER)
|
|
||||||
if f >= 0: s, postparser = s[:f], '\n\n'+s[f+len(DIVIDER):]
|
|
||||||
|
|
||||||
# Create the parser and scanner
|
|
||||||
p = ParserDescription(ParserDescriptionScanner(s))
|
|
||||||
if not p: return
|
|
||||||
|
|
||||||
# Now parse the file
|
|
||||||
t = wrap_error_reporter(p, 'Parser')
|
|
||||||
if not t: return # Error
|
|
||||||
if preparser is not None: t.preparser = preparser
|
|
||||||
if postparser is not None: t.postparser = postparser
|
|
||||||
|
|
||||||
# Check the options
|
|
||||||
for f in t.options.keys():
|
|
||||||
for opt,_,_ in yapps_options:
|
|
||||||
if f == opt: break
|
|
||||||
else:
|
|
||||||
print 'Warning: unrecognized option', f
|
|
||||||
# Add command line options to the set
|
|
||||||
for f in flags.keys(): t.options[f] = flags[f]
|
|
||||||
|
|
||||||
# Generate the output
|
|
||||||
if dump:
|
|
||||||
t.dump_information()
|
|
||||||
else:
|
|
||||||
t.output = open(outputfilename, 'w')
|
|
||||||
t.generate_output()
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
|
||||||
import sys, getopt
|
|
||||||
optlist, args = getopt.getopt(sys.argv[1:], 'f:', ['dump'])
|
|
||||||
if not args or len(args) > 2:
|
|
||||||
print 'Usage:'
|
|
||||||
print ' python', sys.argv[0], '[flags] input.g [output.py]'
|
|
||||||
print 'Flags:'
|
|
||||||
print (' --dump' + ' '*40)[:35] + 'Dump out grammar information'
|
|
||||||
for flag, _, doc in yapps_options:
|
|
||||||
print (' -f' + flag + ' '*40)[:35] + doc
|
|
||||||
else:
|
|
||||||
# Read in the options and create a list of flags
|
|
||||||
flags = {}
|
|
||||||
for opt in optlist:
|
|
||||||
for flag, name, _ in yapps_options:
|
|
||||||
if opt == ('-f', flag):
|
|
||||||
flags[name] = 1
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if opt == ('--dump', ''):
|
|
||||||
flags['dump'] = 1
|
|
||||||
else:
|
|
||||||
print 'Warning - unrecognized option: ', opt[0], opt[1]
|
|
||||||
|
|
||||||
apply(generate, tuple(args), flags)
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,172 +0,0 @@
|
||||||
# Yapps 2.0 Runtime
|
|
||||||
#
|
|
||||||
# This module is needed to run generated parsers.
|
|
||||||
|
|
||||||
from string import *
|
|
||||||
import exceptions
|
|
||||||
import re
|
|
||||||
|
|
||||||
class SyntaxError(Exception):
|
|
||||||
"""When we run into an unexpected token, this is the exception to use"""
|
|
||||||
def __init__(self, pos=-1, msg="Bad Token"):
|
|
||||||
self.pos = pos
|
|
||||||
self.msg = msg
|
|
||||||
def __repr__(self):
|
|
||||||
if self.pos < 0: return "#<syntax-error>"
|
|
||||||
else: return "SyntaxError[@ char " + `self.pos` + ": " + self.msg + "]"
|
|
||||||
|
|
||||||
class NoMoreTokens(Exception):
|
|
||||||
"""Another exception object, for when we run out of tokens"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Scanner:
|
|
||||||
def __init__(self, patterns, ignore, input):
|
|
||||||
"""Patterns is [(terminal,regex)...]
|
|
||||||
Ignore is [terminal,...];
|
|
||||||
Input is a string"""
|
|
||||||
self.tokens = []
|
|
||||||
self.restrictions = []
|
|
||||||
self.input = input
|
|
||||||
self.pos = 0
|
|
||||||
self.ignore = ignore
|
|
||||||
# The stored patterns are a pair (compiled regex,source
|
|
||||||
# regex). If the patterns variable passed in to the
|
|
||||||
# constructor is None, we assume that the class already has a
|
|
||||||
# proper .patterns list constructed
|
|
||||||
if patterns is not None:
|
|
||||||
self.patterns = []
|
|
||||||
for k,r in patterns:
|
|
||||||
self.patterns.append( (k, re.compile(r)) )
|
|
||||||
|
|
||||||
def token(self, i, restrict=0):
|
|
||||||
"""Get the i'th token, and if i is one past the end, then scan
|
|
||||||
for another token; restrict is a list of tokens that
|
|
||||||
are allowed, or 0 for any token."""
|
|
||||||
if i == len(self.tokens): self.scan(restrict)
|
|
||||||
if i < len(self.tokens):
|
|
||||||
# Make sure the restriction is more restricted
|
|
||||||
if restrict and self.restrictions[i]:
|
|
||||||
for r in restrict:
|
|
||||||
if r not in self.restrictions[i]:
|
|
||||||
raise "Unimplemented: restriction set changed"
|
|
||||||
return self.tokens[i]
|
|
||||||
raise NoMoreTokens()
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Print the last 10 tokens that have been scanned in"""
|
|
||||||
output = ''
|
|
||||||
for t in self.tokens[-10:]:
|
|
||||||
output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],`t[3]`)
|
|
||||||
return output
|
|
||||||
|
|
||||||
def scan(self, restrict):
|
|
||||||
"""Should scan another token and add it to the list, self.tokens,
|
|
||||||
and add the restriction to self.restrictions"""
|
|
||||||
# Keep looking for a token, ignoring any in self.ignore
|
|
||||||
while 1:
|
|
||||||
# Search the patterns for the longest match, with earlier
|
|
||||||
# tokens in the list having preference
|
|
||||||
best_match = -1
|
|
||||||
best_pat = '(error)'
|
|
||||||
for p, regexp in self.patterns:
|
|
||||||
# First check to see if we're ignoring this token
|
|
||||||
if restrict and p not in restrict and p not in self.ignore:
|
|
||||||
continue
|
|
||||||
m = regexp.match(self.input, self.pos)
|
|
||||||
if m and len(m.group(0)) > best_match:
|
|
||||||
# We got a match that's better than the previous one
|
|
||||||
best_pat = p
|
|
||||||
best_match = len(m.group(0))
|
|
||||||
|
|
||||||
# If we didn't find anything, raise an error
|
|
||||||
if best_pat == '(error)' and best_match < 0:
|
|
||||||
msg = "Bad Token"
|
|
||||||
if restrict:
|
|
||||||
msg = "Trying to find one of "+join(restrict,", ")
|
|
||||||
raise SyntaxError(self.pos, msg)
|
|
||||||
|
|
||||||
# If we found something that isn't to be ignored, return it
|
|
||||||
if best_pat not in self.ignore:
|
|
||||||
# Create a token with this data
|
|
||||||
token = (self.pos, self.pos+best_match, best_pat,
|
|
||||||
self.input[self.pos:self.pos+best_match])
|
|
||||||
self.pos = self.pos + best_match
|
|
||||||
# Only add this token if it's not in the list
|
|
||||||
# (to prevent looping)
|
|
||||||
if not self.tokens or token != self.tokens[-1]:
|
|
||||||
self.tokens.append(token)
|
|
||||||
self.restrictions.append(restrict)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
# This token should be ignored ..
|
|
||||||
self.pos = self.pos + best_match
|
|
||||||
|
|
||||||
class Parser:
|
|
||||||
def __init__(self, scanner):
|
|
||||||
self._scanner = scanner
|
|
||||||
self._pos = 0
|
|
||||||
|
|
||||||
def _peek(self, *types):
|
|
||||||
"""Returns the token type for lookahead; if there are any args
|
|
||||||
then the list of args is the set of token types to allow"""
|
|
||||||
tok = self._scanner.token(self._pos, types)
|
|
||||||
return tok[2]
|
|
||||||
|
|
||||||
def _scan(self, type):
|
|
||||||
"""Returns the matched text, and moves to the next token"""
|
|
||||||
tok = self._scanner.token(self._pos, [type])
|
|
||||||
if tok[2] != type:
|
|
||||||
raise SyntaxError(tok[0], 'Trying to find '+type)
|
|
||||||
self._pos = 1+self._pos
|
|
||||||
return tok[3]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def print_error(input, err, scanner):
|
|
||||||
"""This is a really dumb long function to print error messages nicely."""
|
|
||||||
p = err.pos
|
|
||||||
# Figure out the line number
|
|
||||||
line = count(input[:p], '\n')
|
|
||||||
print err.msg+" on line "+`line+1`+":"
|
|
||||||
# Now try printing part of the line
|
|
||||||
text = input[max(p-80,0):p+80]
|
|
||||||
p = p - max(p-80,0)
|
|
||||||
|
|
||||||
# Strip to the left
|
|
||||||
i = rfind(text[:p],'\n')
|
|
||||||
j = rfind(text[:p],'\r')
|
|
||||||
if i < 0 or (j < i and j >= 0): i = j
|
|
||||||
if i >= 0 and i < p:
|
|
||||||
p = p - i - 1
|
|
||||||
text = text[i+1:]
|
|
||||||
|
|
||||||
# Strip to the right
|
|
||||||
i = find(text,'\n',p)
|
|
||||||
j = find(text,'\r',p)
|
|
||||||
if i < 0 or (j < i and j >= 0): i = j
|
|
||||||
if i >= 0:
|
|
||||||
text = text[:i]
|
|
||||||
|
|
||||||
# Now shorten the text
|
|
||||||
while len(text) > 70 and p > 60:
|
|
||||||
# Cut off 10 chars
|
|
||||||
text = "..." + text[10:]
|
|
||||||
p = p - 7
|
|
||||||
|
|
||||||
# Now print the string, along with an indicator
|
|
||||||
print '> ',text
|
|
||||||
print '> ',' '*p + '^'
|
|
||||||
print 'List of nearby tokens:', scanner
|
|
||||||
|
|
||||||
def wrap_error_reporter(parser, rule):
|
|
||||||
try: return getattr(parser, rule)()
|
|
||||||
except SyntaxError, s:
|
|
||||||
input = parser._scanner.input
|
|
||||||
try:
|
|
||||||
print_error(input, s, parser._scanner)
|
|
||||||
except ImportError:
|
|
||||||
print 'Syntax Error',s.msg,'on line',1+count(input[:s.pos], '\n')
|
|
||||||
except NoMoreTokens:
|
|
||||||
print 'Could not complete parsing; stopped around here:'
|
|
||||||
print parser._scanner
|
|
||||||
|
|
Loading…
Reference in New Issue