Translate declarations properly, initialized to an initializer expression, a type...
authorNick Downing <nick@ndcode.org>
Sun, 13 Jan 2019 00:36:21 +0000 (11:36 +1100)
committerNick Downing <nick@ndcode.org>
Sun, 13 Jan 2019 00:36:21 +0000 (11:36 +1100)
ansi_c.y
ast.py
c_to_python.py

index ef00cd4..215e832 100644 (file)
--- a/ansi_c.y
+++ b/ansi_c.y
@@ -392,7 +392,8 @@ direct_declarator
        | '(' declarator ')'
        | (?E{ast.AST.DeclaratorArray}direct_declarator '[' (?E{ast.AST.TypeQualifierOrStaticList}type_qualifier_or_static_list_opt) assignment_expression_or_asterisk_opt ']')
        | (?E{ast.AST.DeclaratorFunctionOldStyle}direct_declarator '(' (?E{ast.AST.IdentifierList}identifier_list_opt) ')')
-       | (?E{ast.AST.DeclaratorFunction}direct_declarator '(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) comma_ellipsis_opt ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = False}direct_declarator '(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = True}direct_declarator '(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) ',' ELLIPSIS ')')
        ;
 
 type_qualifier_list_opt
@@ -444,11 +445,13 @@ direct_abstract_declarator
        : '(' direct_abstract_declarator ')'
        | '(' (?E{ast.AST.DeclaratorPointer}'*' (?E{ast.AST.TypeQualifierList}type_qualifier_list_opt) abstract_declarator) ')'
        | (?E{ast.AST.DeclaratorArray}(?E{ast.AST.DeclaratorAbstract})'[' (?E{ast.AST.TypeQualifierOrStaticList}type_qualifier_or_static_list_opt) assignment_expression_or_asterisk_opt ']')
-       | (?E{ast.AST.DeclaratorFunction}(?E{ast.AST.DeclaratorAbstract})'('(?E{ast.AST.ParameterDeclarationList}) (?E{ast.AST.CommaEllipsisEmpty}) ')')
-       | (?E{ast.AST.DeclaratorFunction}(?E{ast.AST.DeclaratorAbstract})'(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) comma_ellipsis_opt ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = False}(?E{ast.AST.DeclaratorAbstract})'('(?E{ast.AST.ParameterDeclarationList}) ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = False}(?E{ast.AST.DeclaratorAbstract})'(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = True}(?E{ast.AST.DeclaratorAbstract})'(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) ',' ELLIPSIS ')')
        | (?E{ast.AST.DeclaratorArray}direct_abstract_declarator '[' (?E{ast.AST.TypeQualifierOrStaticList}type_qualifier_or_static_list_opt) assignment_expression_or_asterisk_opt ']')
-       | (?E{ast.AST.DeclaratorFunction}direct_abstract_declarator '('(?E{ast.AST.ParameterDeclarationList}) (?E{ast.AST.CommaEllipsisEmpty}) ')')
-       | (?E{ast.AST.DeclaratorFunction}direct_abstract_declarator '(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) comma_ellipsis_opt ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = False}direct_abstract_declarator '('(?E{ast.AST.ParameterDeclarationList}) ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = False}direct_abstract_declarator '(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) ')')
+       | (?E{ast.AST.DeclaratorFunction, varargs = True}direct_abstract_declarator '(' (?E{ast.AST.ParameterDeclarationList}parameter_declaration_list) ',' ELLIPSIS ')')
        ;
 
 equals_initializer_opt
@@ -562,8 +565,3 @@ identifier_opt
        : (?E{ast.AST.IdentifierEmpty})
        | IDENTIFIER
        ;
-
-comma_ellipsis_opt
-       : (?E{ast.AST.CommaEllipsisEmpty})
-       | (?E{ast.AST.CommaEllipsis}',' ELLIPSIS)
-       ;
diff --git a/ast.py b/ast.py
index 8acfc01..9de1ef0 100644 (file)
--- a/ast.py
+++ b/ast.py
@@ -5,6 +5,8 @@ class Context:
   def __init__(
     self,
     indent = '',
+    lines = [],
+    top_level = True,
     enclosing_loop = None,
     translate_identifier = {
       'NULL': 'None',
@@ -14,6 +16,8 @@ class Context:
     }
   ):
     self.indent = indent
+    self.lines = lines
+    self.top_level = top_level
     self.enclosing_loop = enclosing_loop
     self.translate_identifier = translate_identifier
 
@@ -131,17 +135,12 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.DeclarationOrStatement({0:s})'.format(', '.join(params))
     # GENERATE END
-    def translate(self, context):
-      AST.Element.translate(self, context)
-      element.set_text(
-        self,
-        0,
-        '{0:s}{1:s}'.format(context.indent, element.get_text(self, 0))
+    def translate_declaration_or_statement(self, context):
+      text = element.to_text(self).strip()
+      assert text[-1] == ';'
+      context.lines.append(
+        '{0:s}{1:s}\n'.format(context.indent, text[:-1])
       )
-      text = element.get_text(self, len(self))
-      if text[-1:] == ';':
-        text = text[:-1]
-      element.set_text(self, len(self), '{0:s}\n'.format(text))
 
   class Statement(DeclarationOrStatement):
     # GENERATE ELEMENT() BEGIN
@@ -228,6 +227,8 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.Expression({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_expression(self, context):
+      return element.to_text(self).strip()
 
   # type analysis
   class Type(element.Element):
@@ -257,6 +258,8 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.Type({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_zero(self, context):
+      raise NotImplementedError
 
   class TypeVoid(Type):
     # GENERATE ELEMENT() BEGIN
@@ -349,6 +352,8 @@ class AST(element.Element):
     # GENERATE END
     def __str__(self):
       return '{0:s}int{1:d}'.format(['u', ''][int(self.signed)], self.bits)
+    def translate_zero(self, context):
+      return '0' if context.top_level else 'None'
 
   class TypeFloat(Type):
     # GENERATE ELEMENT(int complex, int bits) BEGIN
@@ -414,6 +419,8 @@ class AST(element.Element):
         ['', 'i', 'c'][int(self.complex)],
         self.bits
       )
+    def translate_zero(self, context):
+      return '0.' if context.top_level else 'None'
 
   class TypeBool(Type):
     # GENERATE ELEMENT() BEGIN
@@ -444,6 +451,8 @@ class AST(element.Element):
     # GENERATE END
     def __str__(self):
       return 'bool'
+    def translate_zero(self, context):
+      return 'False' if context.top_level else 'None'
 
   class TypePointer(Type):
     # GENERATE ELEMENT(ref target_type) BEGIN
@@ -489,6 +498,9 @@ class AST(element.Element):
     # GENERATE END
     def __str__(self):
       return 'pointer<{0:s}>'.format(str(self.target_type))
+    def translate_zero(self, context):
+      assert isinstance(target_type, TypeInt) and target_type.bits == 8
+      return '\'\'' if context.top_level else 'None'
 
   class TypeArray(Type):
     # GENERATE ELEMENT(ref element_type, int element_count) BEGIN
@@ -556,6 +568,12 @@ class AST(element.Element):
           str(self.element_count)
         )
       )
+    def translate_zero(self, context):
+      return '[{0:s}]'.format(
+        ', '.join(
+          [self.element_type.translate_zero(context)] * self.element_count
+        )
+      )
 
   class TypeFunction(Type):
     class Argument(element.Element):
@@ -615,7 +633,7 @@ class AST(element.Element):
           'ABSTRACT' if self.name == '' else self.name
         )
 
-    # GENERATE ELEMENT(ref return_type, bool is_varargs) BEGIN
+    # GENERATE ELEMENT(ref return_type, bool varargs) BEGIN
     def __init__(
       self,
       tag = 'AST_TypeFunction',
@@ -623,7 +641,7 @@ class AST(element.Element):
       text = '',
       children = [],
       return_type = None,
-      is_varargs = False
+      varargs = False
     ):
       AST.Type.__init__(
         self,
@@ -633,26 +651,26 @@ class AST(element.Element):
         children
       )
       self.return_type = return_type
-      self.is_varargs = (
-        element.deserialize_bool(is_varargs)
-      if isinstance(is_varargs, str) else
-        is_varargs
+      self.varargs = (
+        element.deserialize_bool(varargs)
+      if isinstance(varargs, str) else
+        varargs
       )
     def serialize(self, ref_list):
       AST.Type.serialize(self, ref_list)
       self.set('return_type', element.serialize_ref(self.return_type, ref_list))
-      self.set('is_varargs', element.serialize_bool(self.is_varargs))
+      self.set('varargs', element.serialize_bool(self.varargs))
     def deserialize(self, ref_list):
       AST.Type.deserialize(self, ref_list)
       self.return_type = element.deserialize_ref(self.get('return_type', '-1'), ref_list)
-      self.is_varargs = element.deserialize_bool(self.get('is_varargs', 'false'))
+      self.varargs = element.deserialize_bool(self.get('varargs', 'false'))
     def copy(self, factory = None):
       result = AST.Type.copy(
         self,
         TypeFunction if factory is None else factory
       )
       result.return_type = self.return_type
-      result.is_varargs = self.is_varargs
+      result.varargs = self.varargs
       return result
     def repr_serialize(self, params):
       AST.Type.repr_serialize(self, params)
@@ -660,9 +678,9 @@ class AST(element.Element):
         params.append(
           'return_type = {0:s}'.format(repr(self.return_type))
         )
-      if self.is_varargs != False:
+      if self.varargs != False:
         params.append(
-          'is_varargs = {0:s}'.format(repr(self.is_varargs))
+          'varargs = {0:s}'.format(repr(self.varargs))
         )
     def __repr__(self):
       params = []
@@ -793,78 +811,9 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.BlockItemList({0:s})'.format(', '.join(params))
     # GENERATE END
-    def translate(self, context):
-      result = []
+    def translate_block_item_list(self, context):
       for i in self:
-        if isinstance(i, AST.StatementBlock):
-          assert isinstance(i[0], AST.BlockItemList)
-          i[0].translate(context)
-          result.extend(i[0])
-        else:
-          i.translate(context)
-          result.append(i)
-      self[:] = result
-      if len(self) == 0:
-        element.set_text(self, 0, '{0:s}pass\n'.format(context.indent))
-      else:
-        for i in range(len(self) + 1):
-          element.set_text(self, i, '')
-
-  class CommaEllipsis(Element):
-    # GENERATE ELEMENT() BEGIN
-    def __init__(
-      self,
-      tag = 'AST_CommaEllipsis',
-      attrib = {},
-      text = '',
-      children = []
-    ):
-      AST.Element.__init__(
-        self,
-        tag,
-        attrib,
-        text,
-        children
-      )
-    def copy(self, factory = None):
-      result = AST.Element.copy(
-        self,
-        CommaEllipsis if factory is None else factory
-      )
-      return result
-    def __repr__(self):
-      params = []
-      self.repr_serialize(params)
-      return 'ast.AST.CommaEllipsis({0:s})'.format(', '.join(params))
-    # GENERATE END
-
-  class CommaEllipsisEmpty(Element):
-    # GENERATE ELEMENT() BEGIN
-    def __init__(
-      self,
-      tag = 'AST_CommaEllipsisEmpty',
-      attrib = {},
-      text = '',
-      children = []
-    ):
-      AST.Element.__init__(
-        self,
-        tag,
-        attrib,
-        text,
-        children
-      )
-    def copy(self, factory = None):
-      result = AST.Element.copy(
-        self,
-        CommaEllipsisEmpty if factory is None else factory
-      )
-      return result
-    def __repr__(self):
-      params = []
-      self.repr_serialize(params)
-      return 'ast.AST.CommaEllipsisEmpty({0:s})'.format(', '.join(params))
-    # GENERATE END
+        i.translate_declaration_or_statement(context)
 
   class Declaration(DeclarationOrStatement):
     # GENERATE ELEMENT() BEGIN
@@ -893,6 +842,21 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.Declaration({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_declaration_or_statement(self, context):
+      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)
+            )
+          )
+        )
 
   class DeclarationList(Element):
     # GENERATE ELEMENT() BEGIN
@@ -965,7 +929,7 @@ class AST(element.Element):
       text = '',
       children = []
     ):
-      element.Element.__init__(
+      AST.Declarator.__init__(
         self,
         tag,
         attrib,
@@ -973,7 +937,7 @@ class AST(element.Element):
         children
       )
     def copy(self, factory = None):
-      result = element.Element.copy(
+      result = AST.Declarator.copy(
         self,
         DeclaratorAbstract if factory is None else factory
       )
@@ -995,7 +959,7 @@ class AST(element.Element):
       text = '',
       children = []
     ):
-      element.Element.__init__(
+      AST.Declarator.__init__(
         self,
         tag,
         attrib,
@@ -1003,7 +967,7 @@ class AST(element.Element):
         children
       )
     def copy(self, factory = None):
-      result = element.Element.copy(
+      result = AST.Declarator.copy(
         self,
         DeclaratorArray if factory is None else factory
       )
@@ -1053,43 +1017,63 @@ class AST(element.Element):
     # GENERATE END
 
   class DeclaratorFunction(Declarator):
-    # GENERATE ELEMENT() BEGIN
+    # GENERATE ELEMENT(bool varargs) BEGIN
     def __init__(
       self,
       tag = 'AST_DeclaratorFunction',
       attrib = {},
       text = '',
-      children = []
+      children = [],
+      varargs = False
     ):
-      element.Element.__init__(
+      AST.Declarator.__init__(
         self,
         tag,
         attrib,
         text,
         children
       )
+      self.varargs = (
+        element.deserialize_bool(varargs)
+      if isinstance(varargs, str) else
+        varargs
+      )
+    def serialize(self, ref_list):
+      AST.Declarator.serialize(self, ref_list)
+      self.set('varargs', element.serialize_bool(self.varargs))
+    def deserialize(self, ref_list):
+      AST.Declarator.deserialize(self, ref_list)
+      self.varargs = element.deserialize_bool(self.get('varargs', 'false'))
     def copy(self, factory = None):
-      result = element.Element.copy(
+      result = AST.Declarator.copy(
         self,
         DeclaratorFunction if factory is None else factory
       )
+      result.varargs = self.varargs
       return result
+    def repr_serialize(self, params):
+      AST.Declarator.repr_serialize(self, params)
+      if self.varargs != False:
+        params.append(
+          'varargs = {0:s}'.format(repr(self.varargs))
+        )
     def __repr__(self):
       params = []
       self.repr_serialize(params)
       return 'ast.AST.DeclaratorFunction({0:s})'.format(', '.join(params))
     # GENERATE END
     def get_type_and_name(self, base_type):
-      func_type = TypeFunction(
-        return_type = base_type,
-        is_varargs = self[2].is_varargs,
-      )
-      for parameter_declaration in self[1]:
-        type, name = parameter_declaration[1].get_type_and_name(
-          parameter_declaration[0].get_type()
+      children = []
+      for i in self[1]:
+        type, name = i[1].get_type_and_name(i[0].get_type())
+        children.append(AST.TypeFunction.Argument(type = type, name = name))
+      return self[0].get_type_and_name(
+        AST.TypeFunction(
+          children = children,
+          return_type = base_type,
+          varargs = self.varargs,
         )
-        func_type.append(TypeFunction.Argument(type = type, name = name))
-      return self[0].get_type_and_name(func_type)
+      )
 
   class DeclaratorFunctionOldStyle(Declarator):
     # GENERATE ELEMENT() BEGIN
@@ -1158,7 +1142,7 @@ class AST(element.Element):
       text = '',
       children = []
     ):
-      element.Element.__init__(
+      AST.Declarator.__init__(
         self,
         tag,
         attrib,
@@ -1166,7 +1150,7 @@ class AST(element.Element):
         children
       )
     def copy(self, factory = None):
-      result = element.Element.copy(
+      result = AST.Declarator.copy(
         self,
         DeclaratorPointer if factory is None else factory
       )
@@ -3229,7 +3213,7 @@ class AST(element.Element):
       return 'ast.AST.ExpressionSubtractAssignment({0:s})'.format(', '.join(params))
     # GENERATE END
 
-  class FunctionDefinition(Element):
+  class FunctionDefinition(DeclarationOrStatement):
     # GENERATE ELEMENT() BEGIN
     def __init__(
       self,
@@ -3238,7 +3222,7 @@ class AST(element.Element):
       text = '',
       children = []
     ):
-      AST.Element.__init__(
+      AST.DeclarationOrStatement.__init__(
         self,
         tag,
         attrib,
@@ -3246,7 +3230,7 @@ class AST(element.Element):
         children
       )
     def copy(self, factory = None):
-      result = AST.Element.copy(
+      result = AST.DeclarationOrStatement.copy(
         self,
         FunctionDefinition if factory is None else factory
       )
@@ -3256,18 +3240,23 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.FunctionDefinition({0:s})'.format(', '.join(params))
     # GENERATE END
-    def translate(self, context):
-      assert len(self) == 4
-      del self[0]
-      self[0].translate(context)
-      del self[1]
+    def translate_declaration_or_statement(self, context):
+      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(
+          context.indent,
+          name,
+          ', '.join([i.name for i in type])
+        )
+      )
       indent_save = context.indent
       context.indent += '  '
-      self[1].translate(context)
+      assert context.top_level
+      context.top_level = False
+      self[3].translate_block_item_list(context)
+      context.top_level = True
       context.indent = indent_save
-      element.set_text(self, 0, '{0:s}def '.format(context.indent))
-      element.set_text(self, 1, ':\n')
-      element.set_text(self, 2, '')
 
   class FunctionSpecifier(Element):
     # GENERATE ELEMENT(int n) BEGIN
@@ -4564,7 +4553,10 @@ class AST(element.Element):
       self.repr_serialize(params)
       return 'ast.AST.TranslationUnit({0:s})'.format(', '.join(params))
     # GENERATE END
+    def translate_translation_unit(self, context):
+      for i in self:
+        i.translate_declaration_or_statement(context)
+
   # GENERATE ELEMENT() BEGIN
   def __init__(
     self,
@@ -4645,8 +4637,6 @@ tag_to_class = {
   'AST_AlignAsType': AST.AlignAsType,
   'AST_ArgumentExpressionList': AST.ArgumentExpressionList,
   'AST_BlockItemList': AST.BlockItemList,
-  'AST_CommaEllipsis': AST.CommaEllipsis,
-  'AST_CommaEllipsisEmpty': AST.CommaEllipsisEmpty,
   'AST_Declaration': AST.Declaration,
   'AST_DeclarationList': AST.DeclarationList,
   'AST_DeclarationSpecifierList': AST.DeclarationSpecifierList,
index e092700..0f2ceb3 100755 (executable)
@@ -25,5 +25,7 @@ import y_tab
 root = y_tab.yyparse(ast.AST.TranslationUnit)
 element.serialize(root, 'a.xml', 'utf-8')
 root = element.deserialize('a.xml', ast.factory, 'utf-8')
-root.translate(ast.Context())
-sys.stdout.write(element.to_text(root))
+
+context = ast.Context()
+root.translate_translation_unit(context)
+sys.stdout.write(''.join(context.lines))