--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -39,24 +39,27 @@ def log(minv, fmt, *args):
if _verbosity >= minv:
print >>sys.stderr, fmt % args
# process command line
op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
op.add_option('-d', '--output-dir', dest='outputdir', default='.',
help='Directory in which to put generated headers')
+op.add_option('-I', '--include', dest='includedirs', action='append',
+ help='Additional directory to search for included protocol specifications')
op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count',
help='Verbose logging (specify -vv or -vvv for very verbose logging)')
op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0,
help="Suppress logging output")
options, files = op.parse_args()
_verbosity = options.verbosity
codedir = options.outputdir
+includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
if not len(files):
op.error("No IPDL files specified")
log(1, 'Generated headers will be placed in "%s"', codedir)
allprotocols = []
@@ -67,17 +70,17 @@ for f in files:
filename = '<stdin>'
else:
fd = open(f)
filename = f
specstring = fd.read()
fd.close()
- ast = ipdl.parse(specstring, filename)
+ ast = ipdl.parse(specstring, filename, includedirs=includedirs)
allprotocols.append,('%sProtocolMsgStart' % ast.protocol.name)
log(2, 'checking types')
if not ipdl.typecheck(ast):
print >>sys.stderr, 'Specification is not well typed.'
sys.exit(1)
--- a/ipc/ipdl/ipdl/__init__.py
+++ b/ipc/ipdl/ipdl/__init__.py
@@ -37,18 +37,18 @@ from cStringIO import StringIO
from ipdl.cgen import IPDLCodeGen
from ipdl.lower import LowerToCxx
from ipdl.parser import Parser
from ipdl.type import TypeCheck
from ipdl.cxx.cgen import CxxCodeGen
-def parse(specstring, filename='<stdin>'):
- return Parser().parse(specstring, filename)
+def parse(specstring, filename='/stdin', includedirs=[ ]):
+ return Parser().parse(specstring, os.path.abspath(filename), includedirs)
def typecheck(ast, errout=sys.stderr):
'''Returns True iff |ast| is well typed. Print errors to |errout| if
it is not.'''
return TypeCheck().check(ast, errout)
def gencxx(ast, outdir):
for hdr in LowerToCxx().lower(ast):
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -54,47 +54,59 @@ class Parser:
# there is one Parser per file
current = None
parseStack = [ ]
parsed = { }
def __init__(self, debug=0):
self.debug = debug
self.filename = None
+ self.includedirs = None
self.loc = None # not always up to date
self.lexer = None
self.parser = None
self.tu = TranslationUnit()
- def parse(self, input, filename):
- realpath = os.path.abspath(filename)
- if realpath in Parser.parsed:
- return Parser.parsed[realpath].tu
+ def parse(self, input, filename, includedirs):
+ assert os.path.isabs(filename)
+
+ if filename in Parser.parsed:
+ return Parser.parsed[filename].tu
self.lexer = lex.lex(debug=self.debug,
optimize=not self.debug,
lextab="ipdl_lextab",
outputdir=_thisdir)
self.parser = yacc.yacc(debug=self.debug,
optimize=not self.debug,
tabmodule="ipdl_yacctab",
outputdir=_thisdir)
self.filename = filename
- self.tu.filename = realpath
+ self.includedirs = includedirs
+ self.tu.filename = filename
- Parser.parsed[realpath] = self
+ Parser.parsed[filename] = self
Parser.parseStack.append(Parser.current)
Parser.current = self
ast = self.parser.parse(input=input, lexer=self.lexer,
debug=self.debug)
Parser.current = Parser.parseStack.pop()
return ast
+ def resolveIncludePath(self, filepath):
+ '''Return the absolute path from which the possibly partial
+|filepath| should be read, or |None| if |filepath| can't be located.'''
+ for incdir in self.includedirs +[ '' ]:
+ realpath = os.path.join(incdir, filepath)
+ if os.path.isfile(realpath):
+ return realpath
+ return None
+
# returns a GCC-style string representation of the include stack.
# e.g.,
# in file included from 'foo.ipdl', line 120:
# in file included from 'bar.ipd', line 12:
# which can be printed above a proper error message or warning
@staticmethod
def includeStackString():
s = ''
@@ -200,19 +212,24 @@ def p_PreambleStmt(p):
def p_CxxIncludeStmt(p):
"""CxxIncludeStmt : INCLUDE STRING"""
p[0] = CxxInclude(locFromTok(p, 1), p[2])
def p_ProtocolIncludeStmt(p):
"""ProtocolIncludeStmt : INCLUDE PROTOCOL STRING"""
loc = locFromTok(p, 1)
Parser.current.loc = loc
+ inc = ProtocolInclude(loc, p[3])
- inc = ProtocolInclude(loc, p[3])
- inc.tu = Parser().parse(open(inc.file).read(), inc.file)
+ path = Parser.current.resolveIncludePath(inc.file)
+ if path is None:
+ print >>sys.stderr, "error: can't locate protocol include file `%s'"% (inc.file)
+ inc.tu = TranslationUnit()
+ else:
+ inc.tu = Parser().parse(open(path).read(), path, Parser.current.includedirs)
p[0] = inc
def p_UsingStmt(p):
"""UsingStmt : USING CxxType"""
p[0] = UsingStmt(locFromTok(p, 1), p[2])
##--------------------
## Protocol definition