slicc: cleanup slicc code and make it less verbose
authorNathan Binkert <nate@binkert.org>
Wed, 6 Jul 2011 01:30:05 +0000 (18:30 -0700)
committerNathan Binkert <nate@binkert.org>
Wed, 6 Jul 2011 01:30:05 +0000 (18:30 -0700)
src/mem/protocol/SConscript
src/mem/slicc/ast/AST.py
src/mem/slicc/main.py
src/mem/slicc/parser.py
src/mem/slicc/symbols/SymbolTable.py
src/mem/slicc/util.py
src/python/m5/util/__init__.py

index 5f64938c6558fd86389878a2056fe1bd1281b99d..47a19aecb05463afb366ab38c610a162ae6360dd 100644 (file)
 # Authors: Nathan Binkert
 
 import os
+import re
 import sys
 
 from os.path import isdir, isfile, join as joinpath
 
+from SCons.Scanner import Classic
+
 Import('*')
 
 if not env['RUBY']:
@@ -54,77 +57,36 @@ for root,dirs,files in os.walk(slicc_dir.srcnode().abspath):
 #
 # Use SLICC
 #
-
-def slicc_scanner(node, env, path):
-    contents = node.get_contents()
-    files = [ line.strip() for line in contents.splitlines() if line ]
-    return files
-
-env.Append(SCANNERS=Scanner(function=slicc_scanner,skeys=['.slicc']))
+env['SLICC_PATH'] = str(protocol_dir)
+slicc_scanner = Classic("SliccScanner", ['.sm', '.slicc'], "SLICC_PATH",
+                        r'''include[ \t]["'](.*)["'];''')
+env.Append(SCANNERS=slicc_scanner)
 
 def slicc_emitter(target, source, env):
     protocol = source[0].get_contents()
     files = [s.srcnode().abspath for s in source[1:]]
-    slicc = SLICC(protocol, debug=True)
-    print "SLICC parsing..."
-    for name in slicc.load(files, verbose=True):
-        print "    %s" % name
-
-    target.extend(sorted(slicc.files()))
-    pdir = str(protocol_dir)
-    hdir = str(html_dir)
-
-    if not isdir(pdir):
-        os.mkdir(pdir)
-    if not isdir(hdir):
-        os.mkdir(hdir)
-
-    print "SLICC Generator pass 1..."
-    slicc.findMachines()
-
-    print "SLICC Generator pass 2..."
-    slicc.generate()
-
-    print "SLICC writing C++ files..."
-    slicc.writeCodeFiles(pdir)
-
-    if env['NO_HTML']:
-        print "skipping HTML file creation"
-    else:
-        print "SLICC writing HTML files..."
-        slicc.writeHTMLFiles(hdir)
+    slicc = SLICC(protocol, verbose=False)
+    slicc.load(files)
+    slicc.process()
+    slicc.writeCodeFiles(protocol_dir.abspath)
+    if not env['NO_HTML']:
+        slicc.writeHTMLFiles(html_dir.abspath)
+
+    target.extend([protocol_dir.File(f) for f in sorted(slicc.files())])
     return target, source
 
 def slicc_action(target, source, env):
     protocol = source[0].get_contents()
-    pdir = str(protocol_dir)
-    hdir = str(html_dir)
-
-    if not isdir(pdir):
-        os.mkdir(pdir)
-    if not isdir(hdir):
-        os.mkdir(hdir)
-
-    slicc = SLICC(protocol, debug=True)
-    files = [str(s) for s in source[1:]]
-    slicc.load(files, verbose=False)
-
-    print "SLICC Generator pass 1..."
-    slicc.findMachines()
-
-    print "SLICC Generator pass 2..."
-    slicc.generate()
-
-    print "SLICC writing C++ files..."
-    slicc.writeCodeFiles(pdir)
-
-    if env['NO_HTML']:
-        print "skipping HTML file creation"
-    else:
-        print "SLICC writing HTML files..."
-        slicc.writeHTMLFiles(hdir)
-
-slicc_builder = Builder(action=slicc_action, emitter=slicc_emitter)
+    files = [s.srcnode().abspath for s in source[1:]]
+    slicc = SLICC(protocol, verbose=True)
+    slicc.load(files)
+    slicc.process()
+    slicc.writeCodeFiles(protocol_dir.abspath)
+    if not env['NO_HTML']:
+        slicc.writeHTMLFiles(html_dir.abspath)
+
+slicc_builder = Builder(action=MakeAction(slicc_action, Transform("SLICC")),
+                        emitter=slicc_emitter)
 
 protocol = env['PROTOCOL']
 sources = [ protocol_dir.File("RubySlicc_interfaces.slicc"),
index d098c86428d5fe03960c6544c70ea0c7dd217e1c..b748671142a439227e1b906f0c0e04f965287ca0 100644 (file)
@@ -30,7 +30,7 @@ from slicc.util import PairContainer, Location
 class AST(PairContainer):
     def __init__(self, slicc, pairs=None):
         self.slicc = slicc
-        self.location = Location(slicc.current_source, slicc.current_line)
+        self.location = slicc.currentLocation()
         self.pairs = {}
         if pairs:
             self.pairs.update(getattr(pairs, "pairs", pairs))
index f8efcc323f7cf691938933cc7046db46c210380c..15eb9d4bea6e6ff7e5e43c9d3403ed2a43e0e802 100644 (file)
@@ -60,6 +60,8 @@ def main(args=None):
                       help="Path where html output goes")
     parser.add_option("-F", "--print-files",
                       help="Print files that SLICC will generate")
+    parser.add_option("--tb", "--traceback", action='store_true',
+                      help="print traceback on error")
     parser.add_option("-q", "--quiet",
                       help="don't print messages")
     opts,files = parser.parse_args(args=args)
@@ -71,30 +73,26 @@ def main(args=None):
     output = nprint if opts.quiet else eprint
 
     output("SLICC v0.4")
-    slicc = SLICC(debug=opts.debug)
-
     output("Parsing...")
-    for filename in slicc.load(files, verbose=True):
-        output("    %s", filename)
+
+    slicc = SLICC(debug=opts.debug)
+    slicc.load(files)
 
     if opts.print_files:
         for i in sorted(slicc.files()):
             print '    %s' % i
     else:
-        output("Generator pass 1...")
-        slicc.findMachines()
-
-        output("Generator pass 2...")
-        slicc.generate()
+        output("Processing AST...")
+        slicc.process()
 
-        output("Generating C++ files...")
+        output("Writing C++ files...")
         slicc.writeCodeFiles(opts.code_path)
 
         if opts.html_path:
-            nprint("Writing HTML files...")
+            output("Writing HTML files...")
             slicc.writeHTMLFiles(opts.html_path)
 
-    eprint("SLICC is Done.")
+    output("SLICC is Done.")
 
 if __name__ == "__main__":
     main()
index eb10c2dc45576b1f3b836990a011fd7fed931a68..596b89f64976dbcad42c206b5748c9a715b06680 100644 (file)
@@ -51,11 +51,16 @@ def read_slicc(sources):
             yield sm_file
 
 class SLICC(Grammar):
-    def __init__(self, protocol, **kwargs):
+    def __init__(self, protocol, verbose=False):
         self.decl_list_vec = []
         self.protocol = protocol
+        self.verbose = verbose
         self.symtab = SymbolTable(self)
 
+    def currentLocation(self):
+        return util.Location(self.current_source, self.current_line,
+                             no_warning=not self.verbose)
+
     def codeFormatter(self, *args, **kwargs):
         code = code_formatter(*args, **kwargs)
         code['protocol'] = self.protocol
@@ -68,7 +73,7 @@ class SLICC(Grammar):
             sys.exit(str(e))
         self.decl_list_vec.append(decl_list)
 
-    def _load(self, *filenames):
+    def load(self, filenames):
         filenames = list(filenames)
         while filenames:
             f = filenames.pop(0)
@@ -76,7 +81,6 @@ class SLICC(Grammar):
                 filenames[0:0] = list(f)
                 continue
 
-            yield f
             if f.endswith(".slicc"):
                 dirname,basename = os.path.split(f)
                 filenames[0:0] = [ os.path.join(dirname, x) \
@@ -85,34 +89,18 @@ class SLICC(Grammar):
                 assert f.endswith(".sm")
                 self.parse(f)
 
-    def load(self, *filenames, **kwargs):
-        verbose = kwargs.pop("verbose", False)
-        if kwargs:
-            raise TypeError
-
-        gen = self._load(*filenames)
-        if verbose:
-            return gen
-        else:
-            # Run out the generator if we don't want the verbosity
-            for foo in gen:
-                pass
-
-    def findMachines(self):
+    def process(self):
         for decl_list in self.decl_list_vec:
             decl_list.findMachines()
 
-    def generate(self):
         for decl_list in self.decl_list_vec:
             decl_list.generate()
 
     def writeCodeFiles(self, code_path):
-        util.makeDir(code_path)
         self.symtab.writeCodeFiles(code_path)
 
-    def writeHTMLFiles(self, code_path):
-        util.makeDir(code_path)
-        self.symtab.writeHTMLFiles(code_path)
+    def writeHTMLFiles(self, html_path):
+        self.symtab.writeHTMLFiles(html_path)
 
     def files(self):
         f = set([
index dd45ac06c0cf98215f9039edbc6aa38a137d427e..81d0768f92ad2ae93af51f3c41437de6cfb3710e 100644 (file)
@@ -25,7 +25,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-from m5.util import code_formatter
+from m5.util import makeDir
 
 from slicc.generate import html
 from slicc.symbols.StateMachine import StateMachine
@@ -42,13 +42,15 @@ class SymbolTable(object):
 
         pairs = {}
         pairs["enumeration"] = "yes"
-        MachineType = Type(self, "MachineType", Location("init", 0), pairs)
+        location = Location("init", 0, no_warning=not slicc.verbose)
+        MachineType = Type(self, "MachineType", location, pairs)
         self.newSymbol(MachineType)
 
         pairs = {}
         pairs["primitive"] = "yes"
         pairs["external"] = "yes"
-        void = Type(self, "void", Location("init", 0), pairs)
+        location = Location("init", 0, no_warning=not slicc.verbose)
+        void = Type(self, "void", location, pairs)
         self.newSymbol(void)
 
     def __repr__(self):
@@ -123,6 +125,8 @@ class SymbolTable(object):
                 yield symbol
 
     def writeCodeFiles(self, path):
+        makeDir(path)
+
         code = self.codeFormatter()
         code('''
 /** Auto generated C++ code started by $__file__:$__line__ */
@@ -139,6 +143,8 @@ class SymbolTable(object):
             symbol.writeCodeFiles(path)
 
     def writeHTMLFiles(self, path):
+        makeDir(path)
+
         machines = list(self.getAllType(StateMachine))
         if len(machines) > 1:
             name = "%s_table.html" % machines[0].ident
index abadc3e30c9b4e00e631676372fbf24a3ccb57cf..83badf46d1e8469041fdd06008bfc58d549bedb4 100644 (file)
 import os
 import sys
 
-def makeDir(path):
-    if os.path.exists(path):
-        if not os.path.isdir(path):
-            raise AttributeError, "%s exists but is not directory" % path
-    else:
-        os.mkdir(path)
-
 class PairContainer(object):
     def __init__(self, pairs=None):
         self.pairs = {}
@@ -53,14 +46,23 @@ class PairContainer(object):
         return self.pairs.get(item, failobj)
 
 class Location(object):
-    def __init__(self, filename, lineno):
+    def __init__(self, filename, lineno, no_warning=False):
+        if not isinstance(filename, basestring):
+            raise AttributeError, \
+                "filename must be a string, found '%s'" % (type(filename), )
+        if not isinstance(lineno, (int, long)):
+            raise AttributeError, \
+                "filename must be an integer, found '%s'" % (type(lineno), )
         self.filename = filename
         self.lineno = lineno
+        self.no_warning = no_warning
 
     def __str__(self):
         return '%s:%d' % (os.path.basename(self.filename), self.lineno)
 
     def warning(self, message, *args):
+        if self.no_warning:
+            return
         if args:
             message = message % args
         #raise Exception, "%s: Warning: %s" % (self, message)
@@ -72,4 +74,4 @@ class Location(object):
         raise Exception, "%s: Error: %s" % (self, message)
         sys.exit("\n%s: Error: %s" % (self, message))
 
-__all__ = [ 'makeDir', 'PairContainer', 'Location' ]
+__all__ = [ 'PairContainer', 'Location' ]
index 69f153bb4c7ff6a646dbc5b807b4a4c785cfd0bc..59178197701929c48088af452a564292b2900b9e 100644 (file)
@@ -176,3 +176,12 @@ def readCommand(cmd, **kwargs):
         raise
 
     return subp.communicate()[0]
+
+def makeDir(path):
+    """Make a directory if it doesn't exist.  If the path does exist,
+    ensure that it is a directory"""
+    if os.path.exists(path):
+        if not os.path.isdir(path):
+            raise AttributeError, "%s exists but is not directory" % path
+    else:
+        os.mkdir(path)