Adding ONOS Segment Routing CLI files to new repo
diff --git a/cli/tools/expr_to_desc.py b/cli/tools/expr_to_desc.py
new file mode 100755
index 0000000..9867d49
--- /dev/null
+++ b/cli/tools/expr_to_desc.py
@@ -0,0 +1,803 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2013 Big Switch Networks, Inc.
+#
+# Licensed under the Eclipse Public License, Version 1.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+#      http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+
+# Simple command description builder.
+#
+
+import os
+import copy
+import fileinput
+import traceback
+import argparse
+
+def parse(*line):
+    if args.p:
+        print line
+
+def debug(*line):
+    if args.d:
+        print line
+
+def verbose(*line):
+    if args.v:
+        print line
+
+def error(*line):
+    print line
+
+
+add_token = ('o', '+')
+front_token = ('o', '^')
+end_token = ('o', '$')
+
+def tokens(line):
+    """
+    Returns the tokenzied line, with a eol token at the end
+    The start-token must be prefixed before parsing
+    """
+    tokens = []
+    i = 0
+    end = len(line)
+    while i < end:
+        # break
+        while line[i] in ' \t\r\n':
+            i += 1
+            if i == end:
+                break
+        if i == end:
+            break
+        if line[i] in '[]{}<>()|':
+            tokens.append(('o', line[i])) # 'o' <= char, op
+            i += 1
+            continue
+        # span.
+        token = ''
+        run_i = i 
+        while not line[run_i] in ' \t[]{}<>|\n':
+            run_i += 1
+            if run_i == end:
+                break
+        tokens.append(('t', line[i:run_i])) # 't' <= token
+        i = run_i
+    #
+    tokens.append(end_token) # 't' <= '$' for eol
+
+    return tokens
+
+priority_dict = {
+           '^'  : 0,       # hat, front of line
+           '$'  : 1,       # newline, end of line
+           ')'  : 2,
+           '('  : 3,
+           '}'  : 4,
+           '{'  : 5,
+           ']'  : 6,
+           '['  : 7,
+           '>'  : 8,
+           '<'  : 9,
+           '|'  : 10,
+           '+'  : 11,
+           }
+
+def priority(tok):
+    if not is_op(tok):
+        return -1 # lower than any with a valid priority, enables push
+    if not tok[1] in priority_dict:
+        return 100 # higher than any with a valid priority, enables push
+    return priority_dict[tok[1]]
+
+def is_op(tok):
+    return tok[0] == 'o'
+
+def is_token(tok):
+    return tok[0] == 't'
+
+def is_field(tok):
+    return tok[0] == 'field'
+
+def is_tree(tok):
+    return tok[0] == 'tree'
+
+def is_list(tok):
+    return type(tok) == list
+
+def op_of(tok):
+    return tok[1]
+
+def token_of(tok):
+    return tok[1]
+
+def field_list_of(tok):
+    return tok[1]
+
+balance = {
+        ']'  : '[',
+        '}'  : '{',
+        '>'  : '<',
+        ')'  : '(',
+        '$'  : '^',
+}
+
+def partner(tok):
+    if is_op(tok):
+        if token_of(tok) in balance:
+            return balance[token_of(tok)]
+    return None
+
+
+stack = []
+
+def print_stack():
+    for s in stack:
+        print s
+
+def push(item):
+    parse("PUSH ", stack, "ADD ", item)
+    stack.append(item)
+
+def pop():
+    parse( "POP", stack )
+    p = stack[-1]
+    del stack[-1]
+    return p
+
+def reset_stack():
+    global stack
+    stack = []
+
+def peek(i = 1):
+    top = len(stack)
+    if top < i:
+        return ('o','^') # <= front of line
+    return stack[-i]
+
+def is_in_order(collect):
+    if is_op(collect[1]) and collect[1][1] == '+':
+        return True
+    return False
+
+def is_either(collect):
+    if is_op(collect[1]) and collect[1][1] == '|':
+        return True
+    return False
+
+def gather_field_list(collect, field_list):
+    if type(collect) == list:
+        for f in collect:
+            gather_field_list(f, field_list)
+    elif is_token(collect):
+        field_list.append(collect)
+    elif is_tree(collect):
+        gather_field_list(token_of(token_of(collect)), field_list)
+    else:
+        field_list.append(field_list)
+
+def gather_field(collect):
+    parse( "GATHER FIELD ", collect)
+    field_list = []
+    if is_token(collect):
+        field_list.append(collect)
+    elif is_tree(collect):
+        gather_field_list(token_of(token_of(collect)), field_list)
+    elif type(collect) == list:
+        gather_field_list(collect, field_list)
+    else:
+        field_list.append(collect)
+    return ('field', field_list)
+
+def tree_builder(collect, tok):
+    result = None
+    op = op_of(tok)
+    parse( "WHAT ", collect, tok)
+    if op == '}': # { stuff } ... select one from the args
+        # XXX early return
+        if len(collect) == 1:
+            result = ('CHOICE ALONE', collect)
+        elif is_either(collect):
+            result = ("CHOICE OF", [c for c in collect if not is_op(c)])
+        elif is_in_order(collect):
+            result = ("CHOICE ORDER", [c for c in collect if not is_op(c)])
+        elif is_tree(collect):
+            result = ('CHOICE TREE', collect)
+        elif is_field(collect):
+            return gather_field(collect)
+        elif is_token(collect):
+            return collect
+        elif is_token(collect):
+            return collect
+        else:
+            result = ("CHOICE TROUBLE", op, collect)
+    elif op == ']': # [ stuff ] ... stuff which is optional
+        if len(collect) == 1:
+            result = ('OPTION ALONE', collect)
+        elif is_either(collect):
+            result = ("OPTION OF", [c for c in collect if not is_op(c)])
+        elif is_in_order(collect):
+            result = ("OPTION ORDER", [c for c in collect if not is_op(c)])
+        elif is_tree(collect):
+            result = ('OPTION TREE', collect)
+        elif is_field(collect):
+            return ('tree', ('OPTION FIELD', collect))
+        elif is_token(collect):
+            result = ('OPTION TOKEN', collect)
+        else:
+            result = ("OPTION TROUBLE", op, collect)
+    elif op == ')': # ( stuff ) ... no semantic meaning,
+        # XXX early return
+        return collect
+    elif op == '>': # description of a field
+        gather = gather_field(collect)
+        parse("GATHERED: ",gather)
+        return gather
+    elif op == '|': # either of
+        result = ('EITHER', [c for c in collect if not is_op(c)])
+    elif op == '+': # sum of
+        result = ('ORDER', [c for c in collect if not is_op(c)])
+    elif op == '$': # eol, collect up any tree's left
+        # XXX syntax error?
+        print "STACK "
+        print_stack()
+        print "TOK ", tok
+        print "COLLECT", collect
+        exit()
+    else:
+        parse('return collect, later tok', tok)
+        return collect
+    parse( "BUILD ", op, type(result))
+    return ('tree', result)
+
+
+def single_token(tok):
+    (which, t) = tok
+    parse( "NEXT", which, t, peek())
+
+    if is_token(tok) and is_token(peek()):
+        # two tokens in a row, pretend the op is '+'
+        push(add_token)
+
+    # is this a <tree><tree> ?
+    if is_tree(peek()) and (is_tree(peek(2)) or is_field(peek(2))):
+        # collect together as many as possible
+        collect = [pop()]
+        while is_tree(peek()) or is_field(peek()):
+            collect.insert(0, pop())
+        push(tree_builder(collect, add_token))
+    # is this a <tree><tree> ?
+    elif (not is_op(peek())) and (not is_op(peek(2))):
+        # collect together as many as possible
+        collect = [pop()]
+        while not is_op(peek()):
+            collect.insert(0, pop())
+        push(tree_builder(collect, add_token))
+
+    if is_op(tok):
+        if not is_op(peek(1)): # item or token or field
+            parse( 'PRIO ', tok, priority(tok), peek(2), priority(peek(2)))
+            while priority(tok) < priority(peek(2)):
+                # collect as many from the same priority
+                last = pop()
+                parse( "-->", stack, tok, last)
+                # uniary op?
+                if is_op(peek()) and partner(tok) == op_of(peek()):  
+                    parse( "UNIARY ")
+                    pop() # <= pop matching op
+                    push(tree_builder(last, tok)) # <= token popped off
+                    parse( "LEAVE", stack, tok)
+                    return # don't push the uniary right op
+
+                collect = last
+                op = tok
+                if is_op(peek()):
+                    op = peek()
+                    parse( "BINARY ", op)
+                    collect = [last]
+                    while is_op(peek()) and \
+                      not (partner(tok) == op_of(peek())) and \
+                      priority(op) == priority(peek()):
+                        parse( "WHY ", op_of(op), priority(op), op_of(peek()), priority(peek()))
+                        collect.insert(0, pop()) # <= op
+                        collect.insert(0, pop()) # <= token
+                    if len(collect) == 1:
+                        print "NOT BINARY", tok, op, peek
+                        exit()
+                parse( "==> ", collect, tok)
+                parse( "__  ", stack)
+                push(tree_builder(collect, op))
+                parse( "SO FAR ", stack)
+                parse( "OP FAR ", tok)
+    push(tok)
+    parse( "LAST", stack, tok)
+ 
+
+#
+def single_line(tokens):
+    reset_stack()
+    for (which, t) in tokens:
+        single_token((which, t))
+
+def all_tokens(token_list):
+    for token in token_list:
+        parse( "ALL TOKEN? ", token)
+        if not is_token(token):
+            return False
+    return True
+
+
+class printer:
+    def __init__(self, form, is_optional, indent = 2):
+        self.form = form
+        self.is_optional = is_optional
+        self.need_optional = False
+        self.indent = indent
+    
+    def __str__(self):
+        return "form %s need %s optional %s indent %s" % (
+            self.form, self.need_optional, self.is_optional, self.indent)
+    
+    def indents(self, extra = 0):
+        return "    " * (self.indent + extra)
+    
+    def to_dict(self):
+        self.form = 'dict'
+
+    def is_dict(self):
+        if self.form == 'dict':
+            return True
+        return False
+
+    def to_tuple(self):
+        self.form = 'tuple'
+
+    def is_tuple(self):
+        if self.form == 'tuple':
+            return True
+        return False
+
+    def more_indent(self, incr = 1):
+        self.indent += incr
+    
+    def less_indent(self, decr = 1):
+        self.indent -= decr
+    
+    def nest(self, incr = 1, form = None, is_optional = None):
+        new = copy.deepcopy(self)
+        new.indent += 1
+        if form:
+            new.form = form
+        if is_optional:
+            new.is_optional = is_optional
+        return new
+
+class description:
+    def __init__(self):
+        self.desc = []
+        
+    def raw_out(self, line):
+        self.desc.append(line)
+
+    def out(self, line, printer):
+        self.desc.append(printer.indents() + line)
+
+    def out_with_indent(self, line, printer):
+        self.desc.append(printer.indents(1) + line)
+
+    def result(self):
+        return '\n'.join(self.desc)
+
+desc = description()
+
+def single_recurse(tree):
+    """
+    look for nested trees whose leaf only has a single element
+    """
+    return False
+
+def maker_in_order(in_order, printer):
+    debug( "IN_ORDER ", is_tree(in_order), in_order )
+    if is_list(in_order):
+        was_dict = False
+        desc.out('# %d items in order' % len(in_order) , printer)
+        desc.out('# %s ' % printer , printer)
+        if printer.is_dict():
+            printer.to_tuple()
+            desc.out("(", printer)
+            printer.more_indent()
+            was_dict = True
+        do_optional = False
+        if printer.is_optional:
+            if not was_dict:
+                desc.out("(", printer)
+                printer.more_indent()
+            do_optional = True
+            save_need_optional = printer.need_optional
+            printer.need_optional = True
+            printer.is_optional = False
+                
+        for (n, tree) in enumerate(in_order, 1):
+            debug( "IN_ORDER ITEM ", n, is_token(tree), tree)
+            desc.out('# item %d %s' % (n, printer) , printer)
+            maker_items(tree, printer)
+
+        if was_dict or do_optional:
+            printer.less_indent()
+            desc.out("),", printer)
+            if was_dict:
+                printer.to_dict()
+            if do_optional:
+                printer.is_optional = True
+                printer.need_optional = save_need_optional
+
+    elif is_tree(in_order):
+        was_dict = False
+        if printer.is_dict():
+            desc.out("(", printer) # )(
+            desc.out("#in_order2", printer)
+            traceback.print_stack()
+            printer.to_tuple()
+            printer.more_indent()
+            was_dict = True
+        debug( "IN_ORDER TREE ", token_of(in_order) )
+        maker_do_op(token_of(in_order), printer)
+        if was_dict:
+            printer.less_indent()
+            desc.out("),", printer)
+            printer.to_dict()
+    elif is_token(in_order):
+        maker_items(in_order, printer.nest(incr = 1))
+    elif is_field(in_order):
+        maker_field(field_list_of(in_order), printer.nest(incr = 1))
+    else:
+        error( "IN_ORDER STUCK" )
+    
+def maker_field(field_list, printer):
+    was_tuple = False
+    if printer.is_tuple:
+        was_tuple = True
+        desc.out("{", printer)
+        printer.more_indent()
+        printer.to_tuple()
+
+    if printer.need_optional:
+        desc.out("'optional' : %s," % printer.is_optional, printer)
+
+    for field in field_list:
+        # Add more items here to provide more field decoration
+        printer.more_indent
+        value = token_of(field)
+        if value.find('=') == -1:
+            desc.out("'field' : '%s'," % value, printer)
+        else:
+            desc.out("'%s' : '%s'," % tuple(value.split('=')), printer)
+        printer.less_indent
+        
+    if was_tuple:
+        printer.less_indent()
+        desc.out( "},", printer )
+        printer.to_dict()
+
+def maker_choice(tree_tuple, printer):
+    debug( 'MAKER_CHOICE', tree_tuple, printer.indent )
+
+    if is_tree(tree_tuple):
+        # XXX some tree's can be squashed.
+        debug( "MAKER_CHOICE ITEM ", tree_tuple )
+        maker_do_op(token_of(tree_tuple), printer)
+        return
+
+    # choice needs to print a dictionary.
+    was_tuple = False
+    if printer.is_tuple():
+        printer.to_dict()
+        was_tuple = True
+
+    desc.out('{', printer)
+    printer.more_indent()
+
+    if printer.is_optional:
+        desc.out("'optional': %s," % printer.is_optional,  printer)
+    desc.out("'choices' : (", printer)
+    desc.out("    # maker_choice", printer)
+
+    if is_list(tree_tuple):
+        debug( "CHOICE LIST", len(tree_tuple), tree_tuple )
+        printer.more_indent()
+        for (n, item) in enumerate(tree_tuple, 1):
+            debug( "CHOICE LIst #%d" % n )
+            debug( "       ITEM ", item )
+            maker_items(item, printer)
+        printer.less_indent()
+    elif is_tree(tree_tuple):
+        debug( "CHOICE TREE" )
+        (tree_which, tree) = tree_tuple[1]
+        # tree_which == 'tree'
+        maker_do_op(token_of(tree_tuple), printer.nest(form = 'tuple', incr = 1))
+    elif is_field(tree_tuple):
+        debug( "CHOICE FIELD", tree_tuple[1] )
+        printer.more_indent()
+        maker_field(field_list_of(tree_tuple), printer)
+        printer.less_indent()
+    else:
+        error( 'MAKER_CHOICE CONFUSED' )
+
+    desc.out(")", printer)
+    printer.less_indent()
+    desc.out('},', printer)
+
+    if was_tuple:
+        printer.to_tuple()
+
+
+def maker_do_op(op_tuple, printer):
+    debug( 'OP=> ', op_tuple )
+    (op, operands) = op_tuple
+    debug( 'OP ', op_tuple, op, operands )
+    if op == 'ORDER':
+        debug( "OP IN_ORDER ", operands )
+        maker_in_order(operands, printer)
+    elif op == 'EITHER':
+        # XXX wrong
+        maker_choice(operands, printer)
+    elif op.startswith('CHOICE'):
+        maker_choice(operands, printer)
+    elif op.startswith('OPTION'):
+        was_optional = printer.is_optional
+        printer.is_optional = True
+        debug( 'OP OPTIONAL', operands )
+        maker_items(operands, printer)
+        printer.is_optional = was_optional
+
+
+def maker_trees(trees, printer):
+    (tree_which, op) = trees
+    maker_do_op(op, printer)
+
+
+def maker_items(items, printer):
+    debug( "ITEMS-> ", type(items), items )
+    if type(items) == list:
+        for item in items:
+            if is_tree(item):
+                debug( "TREE ", item )
+                maker_do_op(item, printer)
+            elif is_field(item):
+                desc.out("{", printer)
+                maker_field(field_list_of(item), printer)
+                if printer.need_optional:
+                    desc.out("'optional' : %s," % printer.is_optional, printer)
+                desc.out( "},", printer)
+            elif is_token(item):
+                desc.out("{", printer)
+                printer.more_indent()
+                desc.out("'token' : '%s'," % token_of(item), printer)
+                if printer.need_optional:
+                    desc.out("'optional' : %s," % printer.is_optional, printer)
+                printer.less_indent()
+                desc.out("},", printer)
+    elif is_tree(items):
+        maker_do_op(token_of(items), printer)
+    elif is_field(items):
+        maker_field(field_list_of(items), printer)
+    elif is_token(items):
+        debug( 'ITEMS TOKEN', items )
+        desc.out( "{", printer)
+        printer.more_indent()
+        desc.out( "'token' : '%s'," % token_of(items), printer)
+        if printer.need_optional:
+            desc.out( "'optional' : %s," % printer.is_optional, printer)
+        printer.less_indent()
+        desc.out( "},", printer)
+    else:
+        error( "ITEMS> STUCK", items )
+    
+
+#
+def maker_args(args, printer):
+    debug( "MAKER_ARGS ", args )
+    (pick, item) = args
+    if pick == 'EITHER':
+        debug( "MAKER_ARGS EITHER ", item )
+        if len(item) >= 1:
+            desc.raw_out( '    args : {')
+            if all_tokens(item):
+                for choice in item:
+                    desc.raw_out("            '%s'," % token_of(choice, 3))
+            else:
+                maker_trees(item, printer)
+            desc.raw_out( '    },' )
+        else:  # exactly one choice
+            desc.raw_out( '    args : { ' )
+            if all_token(item):
+                desc.raw_out("            '%s'," % token_of(item[0]))
+            else:
+                print maker_trees(item, printer)
+            desc.raw_out( '    },' )
+    elif pick.startswith('CHOICE'):
+        debug( "CHOICE", len(item) )
+        if len(item) == 1:
+            maker_args(item)
+        elif is_tree(item) and token_of(item)[0] == 'EITHER':
+            maker_choice(token_of(item), printer)
+        elif is_field(item) or is_token(item):
+            maker_choice(item, printer)
+        else:
+            error( "CHOICE HELP ", item )
+    elif pick.startswith('ORDER'):
+        # ought to choose the form of the printer based on item
+        desc.out("'args' : {", printer)
+        printer.less_indent()
+        maker_in_order(item, printer)
+        printer.less_indent()
+        desc.out('}', printer)
+    elif pick.startswith('OPTION'):
+        printer.is_optional = True
+        desc.raw_out( '     args : {')
+        maker_trees(item, printer)
+        desc.raw_out( '    },')
+    else:
+        error( "MAKER_PICKER HELP ", pick )
+
+saved_input = []
+
+#
+def maker(name_tuple, no_supported, result, printer):
+
+    name = token_of(name_tuple)
+    verbose( 'Name: %s no %s Result %s' % (name, no_supported, result) )
+
+    type = 'add-command-type'
+    mode = 'login'
+    new_mode = 'config-CHANGE'
+    obj_type = None
+    #
+    # command-name@command-type@command-mode@obj-type@new_mode
+    #
+    if name.find('@') >= 0:
+        name_parts = name.split('@')
+        name = name_parts[0]
+        type = name_parts[1]
+        if len(name_parts) > 2:
+            mode = name_parts[2]
+        if len(name_parts) > 3:
+            obj_type = name_parts[3]
+        if len(name_parts) > 4:
+            new_mode = name_parts[4]
+        # name-value pairs?
+
+    debug( "NAME ", (name) )
+    debug( 'command name ',  name )
+    desc.raw_out( '%s_%s_COMMAND_DESCRIPTION = {' % 
+                  (args.n.upper(), name.replace("-","_").upper()))
+    desc.raw_out( "    'name'          : '%s'," % name)
+    desc.raw_out( "    'mode'          : '%s'," % mode)
+    if no_supported == False:
+        desc.raw_out( "    'no-supported'  : False,")
+    desc.raw_out( "    'command-type'  : '%s'," % type)
+    if obj_type:
+        desc.raw_out( "    'obj-type'      : '%s'," % obj_type)
+    if type == 'config-submode':
+        desc.raw_out( "    'submode-name'  : '%s'," % new_mode)
+        desc.raw_out( "    'parent-id'     : None,")
+    desc.raw_out( "    'short-help'    : 'add-short-command-help',")
+    if args.f:
+        desc.raw_out( "    'feature'       : '%s'," % args.f)
+    # if the remaining length is two, ORDER should be popped.
+    desc.raw_out( "    'args' : ( ")
+    maker_items(result, printer)
+    desc.raw_out( "    ),")
+    desc.raw_out( "}")
+    return
+
+    if len(order_list) == 2 and len(order) == 1:
+        build_choice = None
+        if is_tree(order_list[1]):
+            debug( "MAKER TREE.", token_of(order_list[1]) )
+            if token_of(order_list[1])[0].startswith('CHOICE'):
+                choice = token_of(order_list[1])
+                build_choice = order_list[1]
+        if build_choice:
+            desc.out("'args' : {", printer)
+            printer.more_indent()
+            maker_choice(build_choice, printer)
+            printer.less_indent()
+            desc.out( '},', printer)
+        else:
+            print "XXX", order_list
+            print "XXX", order_list[1]
+            desc.out("'args' : (", printer)
+            printer.more_indent()
+            printer.to_tuple()
+            maker_in_order(order_list[1], printer)
+            printer.less_indent()
+            desc.out( '),', printer)
+    elif len(order) > 1:
+        maker_args((order[0], order[1:]), printer)
+    else:
+        desc.raw_out('}')
+
+
+parser = argparse.ArgumentParser(prog='desc_maker')
+parser.add_argument('file')
+parser.add_argument('-p')
+parser.add_argument('-d')
+parser.add_argument('-v')
+parser.add_argument('-n', default = "NEW")
+parser.add_argument('-f')
+args = parser.parse_args()
+
+for line in fileinput.input(args.file):
+
+    line_tokens = tokens(line)
+    if len(line_tokens) < 2: # why 2? even blank lines get eol
+        saved_input.append( "# @ %s" %  line)
+        continue
+    #
+    # remove '[' 'no' ']' if its there, don't forget the leading '^'
+    no_supported = False
+
+    if len(line_tokens) > 1:
+        if token_of(line_tokens[0]) == '#':
+            saved_input.append( "# @ %s" %  line)
+            continue
+        elif token_of(line_tokens[0]) == '[':
+            if len(line_tokens) > 2:
+                if token_of(line_tokens[1]) == 'no':
+                    if len(line_tokens) > 3:
+                        if token_of(line_tokens[2]) == ']':
+                            if len(line_tokens) > 4:
+                                no_supported = True
+                                name = line_tokens[3]
+                                parse_tokens = line_tokens[4:]
+                        else:
+                            print 'Warning: name required after \[ no \']'
+                            continue
+                    else:
+                        print 'Warning: only \'\[ no \]\' allowed as prefix'
+                        continue
+                else:
+                    print 'Warning: only \'\[ no \]\' allowed as prefix'
+                    continue
+            else:
+                print 'Warning: only single \[ in line'
+                continue
+        else:
+            name = line_tokens[0]
+            parse_tokens = line_tokens[1:]
+
+    saved_input.append( "# @ %s" %  line)
+    single_line([front_token] + parse_tokens)
+
+    # should look like ^ tree $
+    if len(stack) == 3 and not is_op(stack[1]):
+        debug( "OK------------------  -> ", token_of(stack[1]) )
+        a_printer = printer('tuple', is_optional = False)
+        desc.out('\n#\n# %s#\n' % line, a_printer)
+        maker(name, no_supported, stack[1], a_printer)
+    else:
+        #
+        # Could peek at the stack to get an idea of the nature of the syntax error
+        print "SYNTAX ERROR", name, stack
+
+#
+#
+
+print "#"
+print "# Command used as input for this run are listed below,"
+print "# Fish the command out by egreping '^# @' "
+print "#"
+
+print ''.join(saved_input)
+print desc.result()