convert enum values to integers

Previously the enum values given to the backends were strings of C code.
Luckily the code was simple enough that it was also valid Python. Moving the
conversion to the frontend makes it easier to move enum definitions into the
input files, and cleans up some pyloxi code.
diff --git a/loxi_front_end/identifiers.py b/loxi_front_end/identifiers.py
index 62759d7..0f35dc6 100644
--- a/loxi_front_end/identifiers.py
+++ b/loxi_front_end/identifiers.py
@@ -56,6 +56,7 @@
                        version, all_idents, idents_by_group)
 
 def add_identifier(name, ofp_name, ofp_group, value, version, all_idents, idents_by_group):
+    assert(isinstance(value, int))
     if name in all_idents:
         all_idents[name]["values_by_version"][version] = value
         if ((all_idents[name]["ofp_name"] != ofp_name or
diff --git a/loxi_front_end/of_h_utils.py b/loxi_front_end/of_h_utils.py
index 26dbac1..ed70a55 100644
--- a/loxi_front_end/of_h_utils.py
+++ b/loxi_front_end/of_h_utils.py
@@ -101,9 +101,9 @@
     for enum in enum_list:
         (name, values) = c_parse_utils.extract_enum_vals(enum)
         for (ident, value) in values:
-            full_ident_list[ident] = str(value).strip()
+            full_ident_list[ident] = value
     for ident, value in defines_list:
-        full_ident_list[ident] = str(value).strip()
+        full_ident_list[ident] = value
 
     # Process enum idents
     for enum in enum_list:
@@ -123,7 +123,7 @@
             rv_list[loxi_name] = py_utils.DotDict(dict(
                 ofp_name = ident,
                 ofp_group = name,
-                value = value_str))
+                value = eval(value_str)))
 
     for ident, value in defines_list:
         loxi_name = translation.loxi_name(ident)
@@ -133,7 +133,7 @@
 
         value_str = fixup_values(ident, value, version, full_ident_list)
         if loxi_name in rv_list:
-            if value_str != rv_list[loxi_name].value:
+            if eval(value_str) != rv_list[loxi_name].value:
                 sys.stderr.write("""
 ERROR: IDENT COLLISION.  Version %s, LOXI Ident %s.
 New ofp_name %s, value %s.
@@ -148,7 +148,7 @@
         rv_list[loxi_name] = py_utils.DotDict(dict(
                 ofp_name = ident,
                 ofp_group = "macro_definitions",
-                value = value_str))
+                value = eval(value_str)))
 
     return rv_list
 
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index 974e6cf..d79dd3c 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -36,6 +36,10 @@
 tag = lambda name: P.Empty().setParseAction(P.replaceWith(name))
 
 word = P.Word(P.alphanums + '_')
+integer = (
+            P.Combine('0x' - P.Word('0123456789abcdefABCDEF') |
+            P.Word('0123456789'))
+          ).setParseAction(lambda x: int(x[0], 0))
 
 identifier = word.copy().setName("identifier")
 
@@ -52,7 +56,7 @@
          s('}') - s(';')
 
 # Enums
-enum_member = P.Group(identifier + s('=') + P.Word(P.alphanums + '_'))
+enum_member = P.Group(identifier + s('=') + integer)
 enum_list = P.Forward()
 enum_list << enum_member + P.Optional(s(',') + P.Optional(enum_list))
 enum = kw('enum') - identifier - s('{') + \
diff --git a/py_gen/templates/const.py b/py_gen/templates/const.py
index 93418a1..ef09585 100644
--- a/py_gen/templates/const.py
+++ b/py_gen/templates/const.py
@@ -37,12 +37,12 @@
 OFP_VERSION = ${version}
 
 :: for (group, idents) in sorted(groups.items()):
-::    idents.sort(key=lambda (ident, value): eval(value) if value != 'OFPVID_NONE' else 0)
+::    idents.sort(key=lambda (ident, value): value)
 # Identifiers from group ${group}
 ::    for (ident, value) in idents:
 ::        if version == 1 and ident.startswith('OFPP_'):
 ::        # HACK loxi converts these to 32-bit
-${ident} = ${"%#x" % (int(value, 16) & 0xffff)}
+${ident} = ${"%#x" % (value & 0xffff)}
 ::        else:
 ${ident} = ${value}
 ::        #endif
@@ -55,7 +55,7 @@
 ::                pass
 ::            elif version == 1 and ident.startswith('OFPP_'):
 ::                # HACK loxi converts these to 32-bit
-    ${"%#x" % (int(value, 16) & 0xffff)}: ${repr(ident)},
+    ${"%#x" % (value & 0xffff)}: ${repr(ident)},
 ::        else:
     ${value}: ${repr(ident)},
 ::            #endif
diff --git a/py_gen/util.py b/py_gen/util.py
index fbb2825..068a234 100644
--- a/py_gen/util.py
+++ b/py_gen/util.py
@@ -76,4 +76,4 @@
 def constant_for_value(version, group, value):
     return (["const." + v["ofp_name"] for k, v in of_g.identifiers.items()
              if k in of_g.identifiers_by_group[group] and
-                eval(v["values_by_version"].get(version, "None")) == value] or [value])[0]
+                v["values_by_version"].get(version, None) == value] or [value])[0]
diff --git a/utest/test_parser.py b/utest/test_parser.py
index 91100ab..33ba545 100755
--- a/utest/test_parser.py
+++ b/utest/test_parser.py
@@ -99,7 +99,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast.asList(), [['enum', 'foo', [['BAR', '1']]]])
+        self.assertEquals(ast.asList(), [['enum', 'foo', [['BAR', 1]]]])
 
     def test_multiple(self):
         src = """\
@@ -110,7 +110,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast.asList(), [['enum', 'foo', [['OFP_A', '1'], ['OFP_B', '2'], ['OFP_C', '3']]]])
+        self.assertEquals(ast.asList(), [['enum', 'foo', [['OFP_A', 1], ['OFP_B', 2], ['OFP_C', 3]]]])
 
     def test_trailing_comma(self):
         src = """\
@@ -121,7 +121,7 @@
 };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast.asList(), [['enum', 'foo', [['OFP_A', '1'], ['OFP_B', '2'], ['OFP_C', '3']]]])
+        self.assertEquals(ast.asList(), [['enum', 'foo', [['OFP_A', 1], ['OFP_B', 2], ['OFP_C', 3]]]])
 
 class TestMetadata(unittest.TestCase):
     def test_version(self):