Get l_to_python working again, implement more necessary features such as sizeof
authorNick Downing <nick@ndcode.org>
Sun, 13 Jan 2019 11:27:41 +0000 (22:27 +1100)
committerNick Downing <nick@ndcode.org>
Sun, 13 Jan 2019 11:27:41 +0000 (22:27 +1100)
ansi_c.y
ast.py
l_to_python.py
tests/scan.l

index 9ef78a0..219638f 100644 (file)
--- a/ansi_c.y
+++ b/ansi_c.y
@@ -98,8 +98,8 @@ unary_expression
        | (?E{ast.AST.ExpressionBitwiseNot, unary_operator = '~'}'~' cast_expression)
        | (?E{ast.AST.ExpressionLogicalNot, unary_operator = 'not '}'!' cast_expression)
        | (?E{ast.AST.ExpressionSizeOfExpression, unary_operator = 'sizeof '}SIZEOF unary_expression)
-       | (?E{ast.AST.ExpressionSizeOfType, unary_operator = 'sizeof '}SIZEOF '(' type_name ')')
-       | (?E{ast.AST.ExpressionAlignOfType, unary_operator = 'alignof '}ALIGNOF '(' type_name ')')
+       | (?E{ast.AST.ExpressionSizeOfType}SIZEOF '(' type_name ')')
+       | (?E{ast.AST.ExpressionAlignOfType}ALIGNOF '(' type_name ')')
        ;
 
 cast_expression
@@ -509,7 +509,7 @@ statement
        | (?E{ast.AST.StatementSwitch}SWITCH '(' expression ')' statement)
        | (?E{ast.AST.StatementWhile}WHILE '(' expression ')' statement)
        | (?E{ast.AST.StatementDoWhile}DO statement WHILE '(' expression ')' ';')
-       | (?E{ast.AST.StatementFor}FOR '(' expression_opt ';' expression_opt ';' expression_opt ')' statement)
+       | (?E{ast.AST.StatementFor}FOR '(' (?E{ast.AST.StatementExpression}expression_opt) ';' expression_opt ';' expression_opt ')' statement)
        | (?E{ast.AST.StatementFor}FOR '(' declaration expression_opt ';' expression_opt ')' statement)
        | (?E{ast.AST.StatementGoto}GOTO IDENTIFIER ';')
        | (?E{ast.AST.StatementContinue}CONTINUE ';')
diff --git a/ast.py b/ast.py
index cf878e1..b54e4fd 100644 (file)
--- a/ast.py
+++ b/ast.py
@@ -364,6 +364,12 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.Type({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_size(self, context):
+      print(self)
+      raise NotImplementedError
+    def translate_type(self, context):
+      print(self)
+      raise NotImplementedError
     def translate_zero(self, context):
       print(self)
       raise NotImplementedError
@@ -459,6 +465,10 @@ class AST(element.Element):
     # GENERATE END
     def __str__(self):
       return '{0:s}int{1:d}'.format(['u', ''][int(self.signed)], self.bits)
+    def translate_size(self, context):
+      return (self.bits + 7) // 8
+    def translate_type(self, context):
+      return 'int'
     def translate_zero(self, context):
       return '0' if context.top_level else 'None'
 
@@ -526,6 +536,10 @@ class AST(element.Element):
         ['', 'i', 'c'][int(self.complex)],
         self.bits
       )
+    def translate_size(self, context):
+      return (self.bits + 7) // 8
+    def translate_type(self, context):
+      return 'float'
     def translate_zero(self, context):
       return '0.' if context.top_level else 'None'
 
@@ -558,6 +572,10 @@ class AST(element.Element):
     # GENERATE END
     def __str__(self):
       return 'bool'
+    def translate_size(self, context):
+      return 1
+    def translate_type(self, context):
+      return 'bool'
     def translate_zero(self, context):
       return 'False' if context.top_level else 'None'
 
@@ -605,8 +623,19 @@ class AST(element.Element):
     # GENERATE END
     def __str__(self):
       return 'pointer<{0:s}>'.format(str(self.target_type))
+    def translate_size(self, context):
+      return 4
+    def translate_type(self, context):
+      assert (
+        isinstance(self.target_type, AST.TypeInt) and
+        self.target_type.bits == 8
+      )
+      return 'str'
     def translate_zero(self, context):
-      assert isinstance(target_type, TypeInt) and target_type.bits == 8
+      assert (
+        isinstance(self.target_type, AST.TypeInt) and
+        self.target_type.bits == 8
+      )
       return '\'\'' if context.top_level else 'None'
 
   class TypeArray(Type):
@@ -675,6 +704,8 @@ class AST(element.Element):
           str(self.element_count)
         )
       )
+    def translate_size(self, context):
+      return self.element_type.translate_type(context) * self.element_count 
     def translate_zero(self, context):
       return '[{0:s}]'.format(
         ', '.join(
@@ -795,15 +826,15 @@ class AST(element.Element):
       return 'ast.AST.TypeFunction({0:s})'.format(', '.join(params))
     # GENERATE END
     def __str__(self):
-      return 'function<{0:s}: {1:s}>'.format(
-        str(self.return_type),
+      return 'function<{0:s} -> {1:s}>'.format(
         (
           'void'
         if len(self) == 0 else
           ', '.join(
-            [str(i) for i in self] + (['...'] if self.is_varargs else [])
+            [str(i) for i in self] + (['...'] if self.varargs else [])
           )
-        )
+        ),
+        str(self.return_type)
       )
 
   # syntax classes
@@ -953,17 +984,18 @@ class AST(element.Element):
       base_type = self[0].get_type()
       for i in self[1]:
         type, name = i[0].get_type_and_name(base_type)
-        context.lines.append(
-          '{0:s}{1:s} = {2:s}\n'.format(
-            context.indent,
-            name,
-            (
-              type.translate_zero(context)
-            if isinstance(i[1], AST.EqualsInitializerEmpty) else
-              i[1].translate_expression(context, 0)
+        if not isinstance(type, AST.TypeFunction):
+          context.lines.append(
+            '{0:s}{1:s} = {2:s}\n'.format(
+              context.indent,
+              name,
+              (
+                type.translate_zero(context)
+              if isinstance(i[1], AST.EqualsInitializerEmpty) else
+                i[1].translate_expression(context, 0)
+              )
             )
           )
-        )
 
   class DeclarationList(element.Element):
     # GENERATE ELEMENT() BEGIN
@@ -2005,6 +2037,15 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.ExpressionCast({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_expression(self, context, precedence):
+      type, _ = self[0][1].get_type_and_name(self[0][0].get_type())
+      text = '{0:s}({1:s})'.format(
+        type.translate_type(context),
+        self[1].translate_expression(context, 0)
+      )
+      if 14 < precedence:
+        text = '({0:s})'.format(text)
+      return text
 
   class ExpressionCharConstant(Expression):
     # GENERATE ELEMENT() BEGIN
@@ -2371,7 +2412,7 @@ class AST(element.Element):
     def translate_expression(self, context, precedence):
       text = '{0:s}.{1:s}'.format(
         self[0].translate_expression(context, 14),
-        element.get_text(self[1], 0)
+        self[1].translate_identifier(context)
       )
       if 14 < precedence:
         text = '({0:s})'.format(text)
@@ -2407,7 +2448,7 @@ class AST(element.Element):
     def translate_expression(self, context, precedence):
       text = '{0:s}->{1:s}'.format(
         self[0].translate_expression(context, 14),
-        element.get_text(self[1], 0)
+        self[1].translate_identifier(context)
       )
       if 14 < precedence:
         text = '({0:s})'.format(text)
@@ -2565,7 +2606,7 @@ class AST(element.Element):
       return 'ast.AST.ExpressionIdentifier({0:s})'.format(', '.join(params))
     # GENERATE END
     def translate_expression(self, context, precedence):
-      return element.get_text(self[0], 0)
+      return self[0].translate_identifier(context)
 
   class ExpressionIndex(Expression):
     # GENERATE ELEMENT() BEGIN
@@ -2663,6 +2704,9 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.Identifier({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_identifier(self, context):
+      text = element.get_text(self, 0)
+      return context.translate_identifier.get(text, text)
 
   class ExpressionLeftShiftAssignment(ExpressionBinary):
     # GENERATE ELEMENT() BEGIN
@@ -3401,6 +3445,9 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.ExpressionSizeOfType({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_expression(self, context, precedence):
+      type, _ = self[0][1].get_type_and_name(self[0][0].get_type())
+      return str(type.translate_size(context))
 
   class ExpressionStringLiteral(Expression):
     # GENERATE ELEMENT() BEGIN
@@ -3429,6 +3476,10 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.ExpressionStringLiteral({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_expression(self, context, precedence):
+      return '\'{0:s}\''.format(
+        element.get_text(self[0], 0).replace('\\"', '"').replace('\'', '\\\'')
+      )
 
   class ExpressionSubtract(ExpressionBinary):
     # GENERATE ELEMENT() BEGIN
@@ -3529,7 +3580,7 @@ class AST(element.Element):
       type, name = self[1].get_type_and_name(self[0].get_type())
       assert isinstance(type, AST.TypeFunction)
       context.lines.append(
-        '{0:s}def {1:s}({2:s}):\n'.format(
+        '\n{0:s}def {1:s}({2:s}):\n'.format(
           context.indent,
           name,
           ', '.join([i.name for i in type])
@@ -3869,6 +3920,12 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.SpecifierQualifierList({0:s})'.format(', '.join(params))
     # GENERATE END
+    def get_type(self):
+      type_specifiers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+      for i in self:
+        if isinstance(i, AST.TypeSpecifier):
+          type_specifiers[i.n] += 1
+      return type_specifiers_to_type[tuple(type_specifiers)]
 
   class StatementBlock(Statement):
     # GENERATE ELEMENT() BEGIN
@@ -4067,6 +4124,12 @@ class AST(element.Element):
       return 'ast.AST.StatementDoWhile({0:s})'.format(', '.join(params))
     # GENERATE END
     def translate_declaration_or_statement(self, context):
+      if (
+        isinstance(self[1], AST.ExpressionIntLiteral) and
+        element.get_text(self[1], 0) == '0'
+      ):
+        self[0].translate_declaration_or_statement(context)
+        return
       context.lines.append('{0:s}while True:\n'.format(context.indent))
       indent_save = context.indent
       context.indent += '  '
@@ -4334,7 +4397,14 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.StatementReturn({0:s})'.format(', '.join(params))
     # GENERATE END
-
+    def translate_declaration_or_statement(self, context):
+      context.lines.append(
+        '{0:s}return {1:s}\n'.format(
+          context.indent,
+          self[0].translate_expression(context, 0)
+        )
+      )
   class StatementSwitch(Statement):
     # GENERATE ELEMENT() BEGIN
     def __init__(
@@ -4892,6 +4962,7 @@ type_specifiers_to_type = {
   (0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0): AST.TypeInt(signed = True, bits = 16),
   (0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0): AST.TypeInt(signed = True, bits = 16),
   (0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0): AST.TypeInt(signed = False, bits = 16),
+  (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0): AST.TypeInt(signed = True, bits = 32),
   (0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0): AST.TypeInt(signed = True, bits = 32),
   (0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0): AST.TypeInt(signed = True, bits = 32),
   (0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0): AST.TypeInt(signed = False, bits = 32),
index d954ba2..024f290 100755 (executable)
@@ -25,10 +25,9 @@ def c_to_python(context, text):
   lex_yy.yytext_len = 0
   lex_yy.unput(text)
   root = y_tab.yyparse(ast.AST.TranslationUnit)
-  root.translate(context)
-  #print('@@@')
-  #xml.etree.ElementTree.dump(root)
-  return element.to_text(root)
+  context.lines = []
+  root.translate_translation_unit(context)
+  return ''.join(context.lines)
 
 root = xml.etree.ElementTree.parse(
   sys.stdin,
@@ -49,6 +48,9 @@ actions = []
 with open('a.c', 'w') as fout:
   def extract(i, parent, indent):
     if i.tag == 'AST_Section1Or2_CodeBlock':
+      node = i[0]
+      assert node.tag == 'AST_Text'
+      indent += '  '
       initial = True
     elif i.tag == 'AST_Section2_Rule_Action':
       if len(i) == 0: # continued actions
@@ -60,10 +62,18 @@ with open('a.c', 'w') as fout:
           element.get_text(parent, 2).rstrip('\t ') + ' /*COLUMN32*/ '
         )
         return
+      node = i[0]
+      assert node.tag == 'AST_Text'
       initial = False
+    elif i.tag == 'AST_Section3':
+      node = i
+      initial = True
     else:
       child_indent = indent
-      if i.tag == 'AST_Section1_StartConditions':
+      if i.tag == 'AST':
+        for j in range(1, len(i) + 1):
+          element.set_text(i, j, element.get_text(i, j).rstrip() + '\n')
+      elif i.tag == 'AST_Section1_StartConditions':
         for j in i:
           assert j.tag == 'AST_Name'
           text = element.get_text(j, 0)
@@ -95,8 +105,8 @@ with open('a.c', 'w') as fout:
       for j in i:
         extract(j, i, child_indent)
       return
-    assert i[0].tag == 'AST_Text' and len(i[0]) == 0
-    text = element.to_text(i[0])
+    assert len(node) == 0
+    text = element.get_text(node, 0)
 
     j = 0
     while j < len(text):
@@ -124,12 +134,12 @@ with open('a.c', 'w') as fout:
         fout.write(line)
     fout.write('@@@\n')
 
-    actions.append((i, parent, indent, initial))
+    actions.append((node, parent, indent, initial))
   extract(root, None, '')
 
 os.system('gcc -I tests/flex_h -E a.c >a.i')
 with open('a.i') as fin:
-  for i, parent, indent, initial in actions:
+  for node, parent, indent, initial in actions:
     lines = []
     line = fin.readline()
     while line != '@@@\n':
@@ -152,7 +162,7 @@ with open('a.i') as fin:
     text = ''.join(lines)
 
     if initial:
-      context.indent = indent + '  '
+      context.indent = indent
       text = c_to_python(context, text)
     else:
       assert parent.tag == 'AST_Section2_Rule'
@@ -163,8 +173,8 @@ with open('a.i') as fin:
         context,
         'void a(void) {{\n{0:s}}}\n'.format(text)
       )
-      assert text[:len(indent) + 9] == indent + 'def a():\n'
-      text = text[len(indent) + 9:]
+      assert text[:len(indent) + 10] == '\n{0:s}def a():\n'.format(indent)
+      text = text[len(indent) + 10:]
       if len(text) == 0:
         text = '\n'
       elif text == '\n':
@@ -179,7 +189,7 @@ with open('a.i') as fin:
           indent
         )
       element.set_text(parent, 2, prefix)
-    element.set_text(i[0], 0, text)
+    element.set_text(node, 0, text)
 
 xml.etree.ElementTree.ElementTree(root).write(
   sys.stdout,
index 73e1b5f..62d9fe1 100644 (file)
@@ -139,7 +139,7 @@ void piece_append(const char *str);
 void piece_insert(int n, const char *str);
 void piece_escape(const char *p, size_t n);
 void piece_flush(size_t n);
-void piece_pack();
+void piece_pack(void);
 
 static void markup_action(const char *text);
 static void markup_option(const char *name, int sense);
@@ -1310,6 +1310,14 @@ void piece_insert(int n, const char *str) {
 void piece_escape(const char *p, size_t n) {
  size_t i, j = 0;
  for (i = 0; i < n; ++i)
+#if 1 /* switch not implemented yet in c_to_python */
+  if (p[i] == '<' || p[i] == '>')
+   j += 4;
+  else if (p[i] == '&')
+   j += 5;
+  else
+   ++j;
+#else
   switch (p[i]) {
   case '<':
   case '>':
@@ -1322,9 +1330,26 @@ void piece_escape(const char *p, size_t n) {
    ++j;
    break;
   }
+#endif
  char *q = malloc(j + 1);
  j = 0;
  for (i = 0; i < n; ++i)
+#if 1 /* switch not implemented yet in c_to_python */
+  if (p[i] == '<') {
+   memcpy(q + j, "&lt;", 4);
+   j += 4;
+  }
+  else if (p[i] == '>') {
+   memcpy(q + j, "&gt;", 4);
+   j += 4;
+  }
+  else if (p[i] == '&') {
+   memcpy(q + j, "&amp;", 5);
+   j += 5;
+  }
+  else
+   q[j++] = p[i];
+#else
   switch (p[i]) {
   case '<':
    memcpy(q + j, "&lt;", 4);
@@ -1342,6 +1367,7 @@ void piece_escape(const char *p, size_t n) {
    q[j++] = p[i];
    break;
   }
+#endif
  q[j] = 0;
  piece[piece1++] = q;
 }
@@ -1351,7 +1377,7 @@ void piece_flush(size_t n) {
  yytext += n;
 }
 
-void piece_pack() {
+void piece_pack(void) {
  int i;
  size_t j = 0;
  for (i = piece0; i < piece1; ++i)