#!/usr/bin/env python
#
# Generate a PStrick version of a yacc grammar file
# WWW: http://se.wtb.tue.nl/~hat/showgrammar/
#
# $Id: showgrammar.py,v 1.2 2000/09/01 10:35:19 hat Exp $
#
import sys,getopt
from spark import GenericScanner, GenericParser
# Global list with tokens
# Should be non-empty when used
globterminallist=[]
#
# --------------------------------------------------
# SCANNER TOKENS
#
class Token:
def __init__(self, type, line, attr=None):
self.type = type
self.attr = attr
self.line = line
def __cmp__(self, o):
return cmp(self.type, o)
def __repr__(self):
if self.attr == None:
return self.type+"@"+str(self.line)
else:
return self.type+"@"+str(self.line)+"("+self.attr+")"
#
# --------------------------------------------------
# SCANNER
#
class GrammarScanner(GenericScanner):
def __init__(self):
GenericScanner.__init__(self)
self.lineno=1
def tokenize(self,input):
self.rv=[]
self.lineno=1
GenericScanner.tokenize(self,input)
return self.rv
#
# Token definitions
#
def t_whitespace(self,s):
r'[ \t]+'
pass
def t_nl(self,s):
r'\n'
self.lineno = self.lineno+1
def t_colon(self,s):
r':'
self.rv.append(Token('colon',self.lineno))
def t_semicol(self,s):
r';'
self.rv.append(Token('semicol',self.lineno))
def t_alt(self,s):
r'\|'
self.rv.append(Token('alt',self.lineno))
def t_iden(self,s):
r'[a-zA-Z][a-zA-Z0-9]*'
t=Token('iden', self.lineno, attr=s)
self.rv.append(t)
def t_start(self,s):
r'%start'
t = Token('start', self.lineno)
self.rv.append(t)
def t_token(self,s):
r'%token'
t = Token('token', self.lineno)
self.rv.append(t)
def t_percperc(self,s):
r'%%'
self.rv.append(Token('percperc', self.lineno))
def scan(input):
data = input.read()
scanner = GrammarScanner()
return scanner.tokenize(data)
#
# --------------------------------------------------
# PARSER
#
class GrammarParser(GenericParser):
def __init__(self,start='gramfile'):
GenericParser.__init__(self,start)
#
# Parse rules
#
def p_gramfile(self,args):
'gramfile ::= seca percperc secb'
return (args[0][0],args[0][1],args[2])
def p_seca_1(self,args):
' seca ::= '
return ([],[])
def p_seca_2(self,args):
' seca ::= seca start iden '
r = args[0]
r[0].append(args[2].attr)
return r
def p_seca_3(self,args):
'seca ::= seca token idenlist'
ret = args[0]
for t in args[2]:
ret[1].append(t)
return ret
def p_idenlist_1(self,args):
'idenlist ::= iden'
return [args[0].attr]
def p_idenlist_2(self,args):
'idenlist ::= idenlist iden'
return args[0]+[args[1].attr]
def p_secb_1(self,args):
'secb ::= '
return []
def p_secb_2(self,args):
'secb ::= secb rule'
return args[0]+args[1]
def p_rule(self,args):
'rule ::= iden colon rulealts semicol'
ret = []
for r in args[2]:
ret.append( (args[0].attr,r) )
return ret
def p_rulealts_1(self,args):
'rulealts ::= seqrule'
return [ args[0] ]
def p_rulealts_2(self,args):
'rulealts ::= rulealts alt seqrule'
return args[0] + [ args[2] ]
def p_seqrule_1(self,args):
'seqrule ::='
return []
def p_seqrule_2(self,args):
'seqrule ::= idenlist'
return args[0]
# parse returns a triple
# ( [ start tokens ] [ tokens ] [ (lhs-iden, [ rhs-sequence ] ) ] )
def parse(tokens):
parser = GrammarParser()
return parser.parse(tokens)
#
# --------------------------------------------------
# GENERATOR
# Works in 2 steps for each set of production rules
# 1: Generate an abstract representation
# 2: Convert to actual LaTeX code
#
#
# First some classes of core graphical elements
#
class Graphic:
def __init__(self,tp):
self.type = tp
def _coord(self,x,y):
return '('+str(x)+','+str(y)+')'
def _label(self,x,y):
return '{p'+str(x)+'_'+str(y)+'}'
class Line(Graphic):
def __init__(self,fx,fy,tx,ty, arr='-'):
Graphic.__init__(self,'line')
self.x1=fx
self.y1=fy
self.x2=tx
self.y2=ty
assert(fx>=-1000 and fx<1000)
assert(fy>=-1000 and fy<1000)
assert(tx>=-1000 and tx<1000)
assert(ty>=-1000 and ty<1000)
self.arrow=arr
def __repr__(self):
return 'Line<'+self._coord(self.x1,self.y1)+self._coord(self.x2,self.y2)+",'"+self.arrow+"'>"
def area(self):
if self.x1<self.x2:
sx=self.x1
bx=self.x2
else:
sx=self.x2
bx=self.x1
if self.y1<self.y2:
sy=self.y1
by=self.y2
else:
sy=self.y2
by=self.y1
return (sx,sy,bx,by)
def mirrorX(self,maxx):
self.x1=maxx-self.x1
self.x2=maxx-self.x2
def mirrorY(self,maxy):
self.y1=maxy-self.y1
self.y2=maxy-self.y2
def shift(self,dx,dy):
self.x1=self.x1+dx
self.y1=self.y1+dy
self.x2=self.x2+dx
self.y2=self.y2+dy
def _ensurelabel(self,output,nodelabels,x,y):
if not nodelabels.has_key( (x,y) ):
nodelabels[(x,y)]=self._label(x,y)
s=self._label(x,y)
output.append( '\\pnode'+self._coord(x,y)+s )
return s
else:
return nodelabels[(x,y)]
def _gencode(self,output,nodelabels):
label1=self._ensurelabel(output,nodelabels,self.x1,self.y1)
label2=self._ensurelabel(output,nodelabels,self.x2,self.y2)
if self.x1 == self.x2:
# vertical line
if self.y1<self.y2:
output.append('\\ncline[angleA=0,angleB=180,arrows='+self.arrow+']'+label1+label2)
else:
output.append('\\ncline[angleA=180,angleB=0,arrows='+self.arrow+']'+label1+label2)
elif self.y1 == self.y2:
# Horizontal line
if self.x1<self.x2:
output.append('\\ncline[angleA=270,angleB=90,arrows='+self.arrow+']'+label1+label2)
else:
output.append('\\ncline[angleA=90,angleB=270,arrows='+self.arrow+']'+label1+label2)
else:
raise "Line not horizontal nor vertical"
class Node(Graphic):
def __init__(self,nx,ny,txt):
Graphic.__init__(self,'node')
self.x=nx
self.y=ny
self.text=txt
if nx<-1000 or nx>1000:
raise "Node x coord out of range"
if ny<-1000 or ny>1000:
raise "Node y coord out of range"
def __repr__(self):
return 'Node<'+self._coord(self.x,self.y)+",'"+self.text+"'>"
def area(self):
return (self.x,self.y,self.x,self.y)
def mirrorX(self,maxx):
self.x=maxx-self.x
def mirrorY(self,maxy):
self.y=maxy-self.y
def shift(self,dx,dy):
self.x=self.x+dx
self.y=self.y+dy
def _gencode(self,output,nodelabels):
global globterminallist
if nodelabels.has_key( (self.x, self.y) ):
raise "Node already defined"
label = self._label(self.x,self.y)
nodelabels[(self.x, self.y)]=label
if len(self.text)==0:
output.append( '\\pnode'+self._coord(self.x,self.y)+label )
else:
assert(len(globterminallist)>0)
if self.text in globterminallist:
#tekst = '{\\rnode'+label+'{\\'+self.text+'}}'
tekst = '{\\rnode'+label+'{\\psframebox{\\'+self.text+'}}}'
else:
tekst = '{\\rnode'+label+'{\\psframebox[framearc=1]{\\'+self.text+'}}}'
output.append( '\\rput'+self._coord(self.x,self.y)+tekst )
class Drawing(Graphic):
def __init__(self):
Graphic.__init__(self,'drawing')
self.contents = []
def __repr__(self):
s='Drawing['
b=0
for c in self.contents:
if b: s=s+','
else: b=1
s=s+c.__repr__()
return s+']'
def area(self):
if len(self.contents)==0:
return (0,0,0,0) # Not entirely correct, but will do
(sx,sy,bx,by)=self.contents[0].area()
for c in self.contents:
(a,b,v,w)=c.area()
if a<sx: sx=a
if b<sy: sy=b
if v>bx: bx=v
if w>by: by=w
return (sx,sy,bx,by)
def mirrorX(self,maxx):
for c in self.contents:
c.mirrorX(maxx)
def mirrorY(self,maxy):
for c in self.contents:
c.mirrorY(maxy)
def shift(self,dx,dy):
for c in self.contents:
c.shift(dx,dy)
def add(self,g):
if g.type == 'line' or g.type == 'node':
self.contents.append(g)
elif g.type == 'drawing':
for c in g.contents:
self.contents.append(c)
else:
raise "Don't know how to add type '"+g.type+"'"
# Append the pspicture to the output
def gencode(self,output):
nodelabels={}
(sx,sy,bx,by)=self.area()
output.append('\\begin{pspicture}'+self._coord(sx,sy)+self._coord(bx,by))
for c in self.contents:
c._gencode(output,nodelabels)
output.append('\\end{pspicture}')
return output
#
# --------------------------------------------------
# BLOCK GENERATOR
#
# A block is a square, with a vertical line on the left and right, and
# horizontal under each-other the alternatives. The generator constructs the
# block upside down, so before outputting the block you are advised to mirror
# it first in Y.
#
class BlockGenerator:
def __init__(self):
pass
# prods is a list of alternatives sequnces, all assumed to be non-empty
# maxlen = max #identifiers on 1 line
# positionemptyrule: 0=do not generate
# 1=generate below (after mirrorring in Y at top)
# 2=generate above (after mirrorring in Y at bottom)
# leftside: 1=connect at bottom, 2=connect at top, 3=connect at both
# rightside: 1=connect at bottom, 2=connect at top, 3=connect at both
def generate(self, prods, maxlen, positionemptyrule, leftside=1, rightside=2):
dr = Drawing()
unfinishedstart=[]
unfinishedend=[]
ypos=0
wrapped=0
if len(prods)==0 and positionemptyrule==0:
raise "Empty block"
if positionemptyrule == 1:
(ypos,wr)=self._generateEmpty(dr,unfinishedstart,unfinishedend,ypos)
assert(wr==0)
for p in prods:
if len(p)==0:
raise "Empty sequence"
(ypos,wr)=self._generateAlt(p,dr,unfinishedstart,unfinishedend,maxlen,ypos)
if wr: wrapped=1
if positionemptyrule == 2:
(ypos,wr)=self._generateEmpty(dr,unfinishedstart,unfinishedend,ypos)
assert(wr==0)
# Left side of the block
miny=10000
if leftside & 1: miny=0
maxy=0
if leftside & 2: maxy=ypos-10
for q in unfinishedstart:
assert(q[0]==0)
if q[1]<miny: miny=q[1]
if q[1]>maxy: maxy=q[1]
if miny!=maxy:
dr.add( Line(0,miny, 0,maxy) )
# Right side of the block
maxx=10
if wrapped: maxx=maxlen*10
miny=10000
if rightside & 1: miny=0
maxy=0
if rightside & 2: maxy=ypos-10
for q in unfinishedend:
if q[0]>maxx: maxx=q[0]
if q[1]<miny: miny=q[1]
if q[1]>maxy: maxy=q[1]
for q in unfinishedend:
dr.add( Line(q[0],q[1], maxx+10,q[1]) )
if miny!=maxy:
dr.add( Line(maxx+10,miny, maxx+10, maxy) )
return dr
def _generateEmpty(self,dr,unfinishedstart,unfinishedend,ypos):
unfinishedstart.append( (0,ypos) )
dr.add( Line(0,ypos, 10,ypos, '->') )
unfinishedend.append( (10,ypos) )
return (ypos+10,0)
def _generateAlt(self,prod,dr,unfinishedstart,unfinishedend,maxlen,ypos):
startx=0
unfinishedstart.append( (startx,ypos) )
wrapped=0
while 1:
if len(prod)>maxlen:
line = prod[:maxlen]
prod=prod[maxlen:]
else:
line = prod
prod=[]
xpos=10
for id in line:
dr.add( Node(xpos,ypos,id) )
xpos=xpos+10
for n in range(10,xpos-10,10):
dr.add( Line(n,ypos,n+10,ypos) )
dr.add( Line(startx,ypos, 10,ypos, '->') )
if len(prod)>0:
assert(maxlen*10 == xpos-10)
dr.add( Line(maxlen*10,ypos, maxlen*10+8,ypos) )
dr.add( Line(maxlen*10+8,ypos, maxlen*10+8,ypos+5) )
dr.add( Line(maxlen*10+8,ypos+5, 2, ypos+5) )
dr.add( Line(2,ypos+5, 2,ypos+10) )
ypos=ypos+10
startx=2
wrapped=1
else:
unfinishedend.append( (xpos-10,ypos) )
ypos=ypos+10
break;
return (ypos,wrapped)
class CodeGenerator:
def __init__(self,mxlen,xunlen,yunlen,wanterrorrules,gennewcmds,newcmdsfname,genheaders,indexcount):
self.errorrulescopied=wanterrorrules
self.maxseqlen = mxlen
self.xunitlen=xunlen
self.yunitlen=yunlen
self.generatenewcommands=gennewcmds
self.newcommandsfname=newcmdsfname
self.genlatexheaders=genheaders
self.index=indexcount
self.blockgen = BlockGenerator()
def _LaTeXHeader(self,output):
if self.genlatexheaders:
output.append('\\documentclass{article}')
output.append('\\usepackage{a4wide}')
output.append('\\usepackage{pstricks}')
output.append('\\usepackage{pst-node}')
output.append('')
output.append('\\psset{xunit='+self.xunitlen+',yunit='+self.yunitlen+'}')
output.append('')
output.append('\\begin{document}')
output.append('')
return output
def _LaTeXFooter(self,output):
if self.genlatexheaders:
output.append('')
output.append('\\end{document}')
return output
def _newCommands(self,tokens,output):
for t in tokens:
output.append('\\newcommand{\\'+t+'}{'+t+'}')
output.append('')
return output
def _findRules(self,lhs,grammar):
prods=[]
for g in grammar:
if g[0]==lhs:
if self.errorrulescopied or 'error' not in g[1]:
prods=prods+[ g[1] ]
return prods
def generate(self, startlist, terminallist, grammar):
global globterminallist
todolist = startlist[:]
donelist = []
output=[]
if self.errorrulescopied: terminallist=terminallist+['error']
globterminallist=terminallist # Fill the global terminallist
while len(todolist)>0:
lhs = todolist[0]
del todolist[0]
# Deal with rules for 'lhs'
prods = self._findRules(lhs,grammar)
output=self.generateSection(lhs,prods,output)
# Update todo/done administration
donelist.append(lhs)
for p in prods:
for i in p:
if i not in todolist and i not in donelist and i not in terminallist and i!='error':
todolist.append(i)
if self.index>0:
index=self.generateIndex(donelist,[])
else:
index=['% Index not generated']
ncmds = []
ncmds.append('% List of tokens')
ncmds.append('%')
ncmds.append('% Terminal symbols')
ncmds = self._newCommands(terminallist,ncmds)
ncmds.append('%')
ncmds.append('% Non-terminal symbols')
ncmds = self._newCommands(donelist,ncmds)
if self.generatenewcommands and len(self.newcommandsfname)>0:
fp = open(self.newcommandsfname,'w')
for nc in ncmds:
fp.write(nc+'\n')
fp.close()
header=[]
header = self._LaTeXHeader(header)
if len(self.newcommandsfname)>0:
header.append('\\input{'+self.newcommandsfname+'}')
else:
for nc in ncmds:
header=header+[nc]
header.append('')
footer=[]
footer=self._LaTeXFooter(footer)
return header+output+index+footer
def _splitEmptyNonempty(self,prods):
empty=0
ne=[]
for p in prods:
if len(p)>0:
ne=ne+[p]
else:
empty=1
return (empty,ne)
# Generate a drawing from left to right with a choice between several
# alternatives
def generateDefault(self,prods,output):
(hasempty,prods)=self._splitEmptyNonempty(prods)
if hasempty:
drawing = self.blockgen.generate(prods,self.maxseqlen,1,1,2)
else:
drawing = self.blockgen.generate(prods,self.maxseqlen,0,1,2)
# Add ingoing and outgoing lines
area=drawing.area()
drawing.add( Line(area[0],area[1], area[0]-5,area[1]) )
drawing.add( Line(area[2],area[3], area[2]+5,area[3]) )
drawing.mirrorY(area[3])
drawing.shift(5,0)
return drawing.gencode(output)
# Empty rule, followed by repetitive selection of one of the sufs
def generateLoopback(self,sufs,output):
drawing = self.blockgen.generate(sufs,self.maxseqlen,0,1,1)
area=drawing.area()
drawing.mirrorX(area[2])
# Add the empty rule above
drawing.shift(0,10)
drawing.add( Line(0,0, 10,0,'->') )
drawing.add( Line(10,0,area[2],0) )
drawing.add( Line(0,10,0,0, '->') )
drawing.add( Line(area[2],0, area[2],10) )
# Add the start and end lines
drawing.shift(5,0)
drawing.add( Line(0,0, 5,0) )
drawing.add( Line(area[2]+5,0, area[2]+5+5,0) )
# Turn it upside down
area=drawing.area()
drawing.mirrorY(area[3])
return drawing.gencode(output)
# Non-empty prefix, followed by 0 or more sequences of one of the suffixes
# and the prefix again. Suffix rule may be empty.
def generateLooparound(self,pre,back,output):
predr=self.blockgen.generate(pre,self.maxseqlen,0,2,2)
prearea=predr.area()
predr.mirrorY(prearea[3])
(hasempty,back)=self._splitEmptyNonempty(back)
if hasempty:
sufdr=self.blockgen.generate(back,self.maxseqlen,1,1,1)
else:
sufdr=self.blockgen.generate(back,self.maxseqlen,0,1,1)
sufarea = sufdr.area()
sufdr.mirrorX(sufarea[2])
sufdr.mirrorY(sufarea[3])
# Find the biggest edge
maxx = prearea[2]
if maxx<sufarea[2]: maxx=sufarea[2]
# Insert the prefix drawing into the suffix drawing
predr.shift(0,sufarea[3]+10)
sufdr.add(predr)
sufdr.add( Line(0,sufarea[3], 0,sufarea[3]+10,'->') )
sufdr.add( Line(-5,sufarea[3]+10, 0,sufarea[3]+10) ) # Entry line
# exit line
sufdr.add( Line(prearea[2],sufarea[3]+10,maxx+5,sufarea[3]+10) )
sufdr.add( Line(maxx,sufarea[3], maxx,sufarea[3]+10) ) # Line down to suffix block
if sufarea[2]<maxx:
sufdr.add( Line(sufarea[2],sufarea[3], maxx,sufarea[3]) )
sufdr.shift(5,0)
return sufdr.gencode(output)
def generatePrefixSuffix(self,pre,suf,output):
(preempty,prerules)=self._splitEmptyNonempty(pre)
if preempty:
predrawing=self.blockgen.generate(prerules, self.maxseqlen, 1,1,2)
else:
predrawing=self.blockgen.generate(prerules, self.maxseqlen, 0,1,2)
prearea = predrawing.area()
predrawing.mirrorY(prearea[3])
predrawing.add( Line(prearea[2],prearea[1], prearea[2],prearea[1]-10,'->') )
predrawing.add( Line(prearea[0]-5,prearea[3], prearea[0],prearea[3]) )
sufdrawing = self.blockgen.generate(suf,self.maxseqlen,0,1,1)
sufarea = sufdrawing.area()
sufdrawing.mirrorY(sufarea[3])
if prearea[2]>sufarea[2]:
sufdrawing.shift(prearea[2]-sufarea[2],0)
sufarea = sufdrawing.area()
elif sufarea[2]>prearea[2]:
predrawing.shift(sufarea[2]-prearea[2],0)
else:
pass # prearea[2]==sufarea[2]
predrawing.shift(0,sufarea[3]+10+10)
sufdrawing.add(predrawing)
sufdrawing.add( Line(sufarea[2],sufarea[3], sufarea[2],sufarea[3]+10,'->') )
sufdrawing.add( Line(sufarea[2],sufarea[3]+10,sufarea[2]-10,sufarea[3]+10,'->') )
if sufarea[2]-10>sufarea[0]:
sufdrawing.add( Line(sufarea[0],sufarea[3]+10, sufarea[2]-10, sufarea[3]+10) )
sufdrawing.add( Line(sufarea[0],sufarea[3]+10, sufarea[0],sufarea[3]) )
sufdrawing.add( Line(sufarea[2],sufarea[3]+10, sufarea[2]+5, sufarea[3]+10) )
# Align the entire drawing
sufarea = sufdrawing.area()
if sufarea[0]!=0 or sufarea[1]!=0:
sufdrawing.shift(-sufarea[0],-sufarea[1])
return sufdrawing.gencode(output)
# Try to split the set of rules in prefixes and suffixes
# Prefix is X ::= <some sequence not using X>
# Suffix is X ::= X <some non-empty sequence not using X>
# Return ( <list prefix rules>, <list suffix rukes>, <bool> )
# bool is 1 if split was successful, 0 otherwise
# suffix rules do not have lhs any more
def _splitPrefixSuffix(self,lhs,prods):
res=([],[],1)
for p in prods:
if len(p)==0:
res=(res[0]+[p],res[1],1)
elif lhs not in p:
res=(res[0]+[p],res[1],1)
elif len(p)>1 and p[0]==lhs and lhs not in p[1:]:
res=(res[0],res[1]+[p[1:]],1)
else:
return ([],[],0)
return res
def generateIndex(self,ntlist,output):
if self.index>0 and len(ntlist)>0:
ntlist.sort()
output.append('\\section*{Index}')
colspec=''
for i in range(0,self.index):
colspec=colspec+'l'
output.append('\\begin{tabular}{'+colspec+'}')
ylen = len(ntlist)/self.index
if len(ntlist)%self.index>0:
ylen=ylen+1
lines=[]
for y in range(0,ylen):
lines.append('')
# Add the columns
while len(ntlist)>0:
# Prefix an & if needed
if len(lines[0])>0:
for y in range(0,ylen):
lines[y]=lines[y]+'\t&'
for y in range(0,ylen):
if len(ntlist)>0:
lhs=ntlist[0]
ntlist=ntlist[1:]
lines[y]=lines[y]+' \\'+lhs+'{}, \\pageref{sec:'+lhs+'}'
for y in range(0,ylen-1):
lines[y]=lines[y]+'\t\\\\'
for y in range(0,ylen):
output.append(lines[y])
output.append('\\end{tabular}')
return output
def generateSection(self,lhs,prods,output):
if self.index==0:
output.append('\\section*{\\'+lhs+'}')
else:
output.append('\\section*{\\'+lhs+'}\\label{sec:'+lhs+'}')
(pre,suf,ok)=self._splitPrefixSuffix(lhs,prods)
# It is not a set rules with the form
# X::= A B C or the form X::= X A B C
# Generate a diagram in default output format
if not ok:
output = self.generateDefault(prods,output)
output.append('')
return output
# rules could be split
# Seperate empty/non empty prefix rules
(preempty,nonemptypreprods)=self._splitEmptyNonempty(pre)
# No sufiixes -> use the default
if len(suf)==0:
output = self.generateDefault(prods,output)
output.append('')
return output
# Empty prefix
if len(pre)==1 and preempty:
output = self.generateLoopback(suf,output)
output.append('')
return output
if len(pre)==1 and not preempty:
# one non-empty prefix
prerule=pre[0]
back=[]
b=1
for s in suf:
if len(s)>=len(prerule) and s[-len(prerule):]==prerule:
back=back+[s[:-len(prerule)]]
else:
b=0
break
if b:
# One prefix, and is also used at the end of all suffixes
# -> Loop around
# Note that back is a shortened version of the sufs
# it may contain empty rules (e.g. X ::= A | X A)
output=self.generateLooparound(pre,back, output)
output.append('')
return output
# Default prefix/suffix diagram
output = self.generatePrefixSuffix(pre,suf,output)
output.append('')
return output
# CODE BELOW NOT REACHED !!
# Real ugly default (mainly for debugging purposes)
for p in prods:
output.append(str(p))
output.append('')
return output
def generate(p,maxlen,xunitlen,yunitlen,wanterrorrules,generatenewcommands,newcommandsfname,genheaders,indexcount):
cg=CodeGenerator(maxlen,xunitlen,yunitlen,wanterrorrules,generatenewcommands,newcommandsfname,genheaders,indexcount)
(sl,tl,g)=p
output=cg.generate(sl,tl,g)
return output
#
# --------------------------------------------------
# Main program
#
if __name__ == '__main__':
# Default program option settings
copyerror=0 # Default do not copy error grammar rules
gennewcommands=0 # Generate a terminal file
genheaders=0
maxlen=7
newcommandsfname=''
xunitlen='1.7mm'
yunitlen='1mm'
indexcount=0
(opts,args) = getopt.getopt(sys.argv[1:],'eghm:t:x:y:i:')
for op in opts:
if op[0]=='-e':
copyerror=1
elif op[0]=='-g':
gennewcommands=1
elif op[0]=='-h':
genheaders=1
elif op[0]=='-m':
maxlen=int(op[1])
elif op[0]=='-t':
newcommandsfname=op[1]
elif op[0]=='-x':
xunitlen=op[1]
elif op[0]=='-y':
yunitlen=op[1]
elif op[0]=='-i':
indexcount=int(op[1])
else:
assert(0) # We should never get here
if len(newcommandsfname)==0:
gennewcommands=0
# Read the input
if len(args)==0:
s=scan(sys.stdin)
elif len(args)==1 or len(args)==2:
input=open(args[0],'r')
s=scan(input)
input.close()
else:
stderr.write('showgrammar: Too many arguments\n')
sys.exit(1)
p=parse(s)
output=generate(p,maxlen,xunitlen,yunitlen,copyerror,gennewcommands,
newcommandsfname,genheaders,indexcount)
# Write the output
if len(args)==0 or len(args)==1:
for l in output:
print l
elif len(args)==2:
outfile=open(args[1],'w')
for l in output:
outfile.write(l+'\n')
outfile.close()
syntax highlighted by Code2HTML, v. 0.9.1