add ports declarations
[sv2nmigen.git] / parse_sv.py
index 82cb55ebe00ccff568edd654d509628ec7c25d92..67ef513dd3abcc0ca034473761d8225e746d9156 100644 (file)
@@ -35,27 +35,95 @@ precedence = [\
               'K_MOD_EQ', 'K_AND_EQ', 'K_OR_EQ'),
     ('right', 'K_XOR_EQ', 'K_LS_EQ', 'K_RS_EQ', 'K_RSS_EQ'),
     ('right', '?', ':', 'K_inside'),
-    ('left', 'K_LOR'), 
-    ('left', 'K_LAND'), 
-    ('left', '|'), 
-    ('left', '^', 'K_NXOR', 'K_NOR'), 
-    ('left', '&', 'K_NAND'), 
-    ('left', 'K_EQ', 'K_NE', 'K_CEQ', 'K_CNE', 'K_WEQ', 'K_WNE'), 
-    ('left', 'K_GE', 'K_LE', '<', '>'), 
-    ('left', 'K_LS', 'K_RS', 'K_RSS'), 
-    ('left', '+', '-'), 
-    ('left', '*', '/', '%'), 
-    ('left', 'K_POW'), 
-    ('left', 'UNARY_PREC'), 
-    ('nonassoc', 'less_than_K_else'), 
-    ('nonassoc', 'K_else'), 
-    ('nonassoc', '('), 
-    ('nonassoc', 'K_exclude'), 
-    ('nonassoc', 'no_timeunits_declaration'), 
-    ('nonassoc', 'one_timeunits_declaration'), 
+    ('left', 'K_LOR'),
+    ('left', 'K_LAND'),
+    ('left', '|'),
+    ('left', '^', 'K_NXOR', 'K_NOR'),
+    ('left', '&', 'K_NAND'),
+    ('left', 'K_EQ', 'K_NE', 'K_CEQ', 'K_CNE', 'K_WEQ', 'K_WNE'),
+    ('left', 'K_GE', 'K_LE', '<', '>'),
+    ('left', 'K_LS', 'K_RS', 'K_RSS'),
+    ('left', '+', '-'),
+    ('left', '*', '/', '%'),
+    ('left', 'K_POW'),
+    ('left', 'UNARY_PREC'),
+    ('nonassoc', 'less_than_K_else'),
+    ('nonassoc', 'K_else'),
+    ('nonassoc', '('),
+    ('nonassoc', 'K_exclude'),
+    ('nonassoc', 'no_timeunits_declaration'),
+    ('nonassoc', 'one_timeunits_declaration'),
     ('nonassoc', 'K_timeunit', 'K_timeprecision')
     ]
-()
+
+
+IVL_VT_NO_TYPE = 'VT_NO_TYPE'
+IVL_VT_BOOL = 'VT_BOOL'
+IVL_VT_LOGIC = 'VT_LOGIC'
+"""
+      IVL_VT_VOID    = 0,  /* Not used */
+      IVL_VT_NO_TYPE = 1,  /* Place holder for missing/unknown type. */
+      IVL_VT_REAL    = 2,
+      IVL_VT_BOOL    = 3,
+      IVL_VT_LOGIC   = 4,
+      IVL_VT_STRING  = 5,
+      IVL_VT_DARRAY  = 6,  /* Array (esp. dynamic array) */
+      IVL_VT_CLASS   = 7,  /* SystemVerilog class instances */
+      IVL_VT_QUEUE   = 8,  /* SystemVerilog queue instances */
+      IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */
+"""
+
+NN_NONE = 'NONE'
+NN_IMPLICIT = 'IMPLICIT'
+NN_IMPLICIT_REG = 'IMPLICIT_REG'
+NN_INTEGER = 'INTEGER'
+NN_WIRE = 'WIRE'
+NN_TRI = 'TRI'
+NN_TRI1 = 'TRI1'
+NN_SUPPLY0 = 'SUPPLY0'
+NN_SUPPLY1 = 'SUPPLY1'
+NN_WAND = 'WAND'
+NN_TRIAND = 'TRIAND'
+NN_TRI0 = 'TRI0'
+NN_WOR = 'WOR'
+NN_TRIOR = 'TRIOR'
+NN_REG = 'REG'
+NN_UNRESOLVED_WIRE = 'UNRESOLVED_WIRE'
+
+NP_NOT_A_PORT = 'NOT_A_PORT'
+NP_PIMPLICIT = 'PIMPLICIT'
+NP_PINPUT = 'PINPUT'
+NP_POUTPUT = 'POUTPUT'
+NP_PINOUT = 'PINOUT'
+NP_PREF = 'PREF'
+
+def indent(s, i=4):
+    st = ''
+    for x in s:
+        st += str(x)
+    res = []
+    for p in st.split('\n'):
+        res.append(' ' * i + p)
+    return '\n'.join(res)
+
+
+class DataType:
+    def __init__(self, typ, signed):
+        self.typ = typ
+        self.signed = signed
+
+def port_decl(comment, dt, name):
+    if dt.dims is None:
+        width = '' # width: 1
+    else:
+        width = dt.dims
+        # XXX TODO, better checking, should be using data structure... *sigh*
+        width = width[1:-1] # strip brackets
+        width = width.split(':')
+        assert width[0] == '0'
+        width = width[1]
+    return 'self.%s = Signal(%s) # %s' % (name, width, comment)
+
 # -------------- RULES ----------------
 ()
 def p_source_text_1(p):
@@ -157,7 +225,7 @@ def p_class_declaration_endlabel_opt_1(p):
     # { class_type_t*tmp = dynamic_cast<class_type_t*> ($2.type);
     #  if (tmp == 0) {
     #        yyerror(@2, "error: class declaration endlabel \"%s\" is not a class name\n", $2.text);
-    #        $$ = 0;
+    #        p[0] = None
     #  } else {
     #        $$ = strdupnew(tmp->name.str());
     #  }
@@ -172,7 +240,7 @@ def p_class_declaration_endlabel_opt_2(p):
 def p_class_declaration_endlabel_opt_3(p):
     '''class_declaration_endlabel_opt :  '''
     print('class_declaration_endlabel_opt_3', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_class_declaration_extends_opt_1(p):
     '''class_declaration_extends_opt : K_extends TYPE_IDENTIFIER '''
@@ -489,6 +557,15 @@ def p_data_declaration_1(p):
 def p_data_type_1(p):
     '''data_type : integer_vector_type unsigned_signed_opt dimensions_opt '''
     print('data_type_1', list(p))
+    use_vtype = p[1]
+    reg_flag = False
+    if (use_vtype == IVL_VT_NO_TYPE):
+        use_vtype = IVL_VT_LOGIC
+        reg_flag = True
+    dt = DataType(use_vtype, signed=p[2])
+    dt.dims = p[3]
+    dt.reg_flag = reg_flag
+    p[0] = dt
     # { ivl_variable_type_t use_vtype = $1;
     #  bool reg_flag = false;
     #  if (use_vtype == IVL_VT_NO_TYPE) {
@@ -504,6 +581,7 @@ def p_data_type_1(p):
 def p_data_type_2(p):
     '''data_type : non_integer_type '''
     print('data_type_2', list(p))
+    p[0] = p[1]
     # { real_type_t*tmp = new real_type_t($1);
     #  FILE_NAME(tmp, @1);
     #  $$ = tmp;
@@ -512,6 +590,7 @@ def p_data_type_2(p):
 def p_data_type_3(p):
     '''data_type : struct_data_type '''
     print('data_type_3', list(p))
+    p[0] = p[1]
     # { if (!$1->packed_flag) {
     #        yyerror(@1, "sorry: Unpacked structs not supported.");
     #  }
@@ -607,7 +686,7 @@ def p_data_type_or_implicit_3(p):
 def p_data_type_or_implicit_4(p):
     '''data_type_or_implicit :  '''
     print('data_type_or_implicit_4', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_data_type_or_implicit_or_void_1(p):
     '''data_type_or_implicit_or_void : data_type_or_implicit '''
@@ -810,12 +889,12 @@ def p__embed4_function_declaration(p):
 def p_import_export_1(p):
     '''import_export : K_import '''
     print('import_export_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_import_export_2(p):
     '''import_export : K_export '''
     print('import_export_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_implicit_class_handle_1(p):
     '''implicit_class_handle : K_this '''
@@ -863,23 +942,23 @@ def p_inside_expression_1(p):
     '''inside_expression : expression K_inside '{' open_range_list '}' '''
     print('inside_expression_1', list(p))
     # { yyerror(@2, "sorry: \"inside\" expressions not supported yet.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_integer_vector_type_1(p):
     '''integer_vector_type : K_reg '''
     print('integer_vector_type_1', list(p))
-    # { $$ = IVL_VT_NO_TYPE; }
+    p[0] = IVL_VT_NO_TYPE
 ()
 def p_integer_vector_type_2(p):
     '''integer_vector_type : K_bit '''
     print('integer_vector_type_2', list(p))
-    # { $$ = IVL_VT_BOOL; }
+    p[0] = IVL_VT_BOOL
 ()
 def p_integer_vector_type_3(p):
     '''integer_vector_type : K_logic '''
     print('integer_vector_type_3', list(p))
-    # { $$ = IVL_VT_LOGIC; }
+    p[0] = IVL_VT_LOGIC
 ()
 def p_integer_vector_type_4(p):
     '''integer_vector_type : K_bool '''
@@ -905,7 +984,7 @@ def p_jump_statement_1(p):
     '''jump_statement : K_break ';' '''
     print('jump_statement_1', list(p))
     # { yyerror(@1, "sorry: break statements not supported.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_jump_statement_2(p):
@@ -957,13 +1036,13 @@ def p_loop_statement_2(p):
     print('loop_statement_2', list(p))
     # { pform_name_t tmp_hident;
     #  tmp_hident.push_back(name_component_t(lex_strings.make($4)));
-    # 
+    #
     #  PEIdent*tmp_ident = pform_new_ident(tmp_hident);
     #  FILE_NAME(tmp_ident, @4);
-    # 
+    #
     #  PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13);
     #  FILE_NAME(tmp_for, @1);
-    # 
+    #
     #  pform_pop_scope();
     #  vector<Statement*>tmp_for_list (1);
     #  tmp_for_list[0] = tmp_for;
@@ -1010,7 +1089,7 @@ def p_loop_statement_7(p):
     '''loop_statement : K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' _embed1_loop_statement statement_or_null '''
     print('loop_statement_7', list(p))
     # { PForeach*tmp_for = pform_make_foreach(@1, $3, $5, $9);
-    # 
+    #
     #  pform_pop_scope();
     #  vector<Statement*>tmp_for_list(1);
     #  tmp_for_list[0] = tmp_for;
@@ -1023,42 +1102,42 @@ def p_loop_statement_7(p):
 def p_loop_statement_8(p):
     '''loop_statement : K_for '(' lpvalue '=' expression ';' expression ';' error ')' statement_or_null '''
     print('loop_statement_8', list(p))
-    # { $$ = 0;
+    # { p[0] = None
     #  yyerror(@1, "error: Error in for loop step assignment.");
     #       }
 ()
 def p_loop_statement_9(p):
     '''loop_statement : K_for '(' lpvalue '=' expression ';' error ';' for_step ')' statement_or_null '''
     print('loop_statement_9', list(p))
-    # { $$ = 0;
+    # { p[0] = None
     #  yyerror(@1, "error: Error in for loop condition expression.");
     #       }
 ()
 def p_loop_statement_10(p):
     '''loop_statement : K_for '(' error ')' statement_or_null '''
     print('loop_statement_10', list(p))
-    # { $$ = 0;
+    # { p[0] = None
     #  yyerror(@1, "error: Incomprehensible for loop.");
     #       }
 ()
 def p_loop_statement_11(p):
     '''loop_statement : K_while '(' error ')' statement_or_null '''
     print('loop_statement_11', list(p))
-    # { $$ = 0;
+    # { p[0] = None
     #  yyerror(@1, "error: Error in while loop condition.");
     #       }
 ()
 def p_loop_statement_12(p):
     '''loop_statement : K_do statement_or_null K_while '(' error ')' ';' '''
     print('loop_statement_12', list(p))
-    # { $$ = 0;
+    # { p[0] = None
     #  yyerror(@1, "error: Error in do/while loop condition.");
     #       }
 ()
 def p_loop_statement_13(p):
     '''loop_statement : K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null '''
     print('loop_statement_13', list(p))
-    # { $$ = 0;
+    # { p[0] = None
     #         yyerror(@4, "error: Errors in foreach loop variables list.");
     #       }
 ()
@@ -1071,7 +1150,7 @@ def p__embed0_loop_statement(p):
     #  PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
     #  FILE_NAME(tmp, @1);
     #  current_block_stack.push(tmp);
-    # 
+    #
     #  list<decl_assignment_t*>assign_list;
     #  decl_assignment_t*tmp_assign = new decl_assignment_t;
     #  tmp_assign->name = lex_strings.make($4);
@@ -1085,11 +1164,11 @@ def p__embed1_loop_statement(p):
     #  char for_block_name[64];
     #  snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter);
     #  foreach_counter += 1;
-    # 
+    #
     #  PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
     #  FILE_NAME(tmp, @1);
     #  current_block_stack.push(tmp);
-    # 
+    #
     #  pform_make_foreach_declarations(@1, $5);
     #       }
 ()
@@ -1535,21 +1614,21 @@ def p_procedural_assertion_statement_1(p):
     '''procedural_assertion_statement : K_assert '(' expression ')' statement %prec less_than_K_else '''
     print('procedural_assertion_statement_1', list(p))
     # { yyerror(@1, "sorry: Simple immediate assertion statements not implemented.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_procedural_assertion_statement_2(p):
     '''procedural_assertion_statement : K_assert '(' expression ')' K_else statement '''
     print('procedural_assertion_statement_2', list(p))
     # { yyerror(@1, "sorry: Simple immediate assertion statements not implemented.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_procedural_assertion_statement_3(p):
     '''procedural_assertion_statement : K_assert '(' expression ')' statement K_else statement '''
     print('procedural_assertion_statement_3', list(p))
     # { yyerror(@1, "sorry: Simple immediate assertion statements not implemented.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_property_qualifier_1(p):
@@ -1613,12 +1692,12 @@ def p_real_or_realtime_2(p):
 def p_signing_1(p):
     '''signing : K_signed '''
     print('signing_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_signing_2(p):
     '''signing : K_unsigned '''
     print('signing_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_simple_type_or_string_1(p):
     '''simple_type_or_string : integer_vector_type '''
@@ -1712,7 +1791,7 @@ def p_statement_or_null_1(p):
 def p_statement_or_null_2(p):
     '''statement_or_null : attribute_list_opt ';' '''
     print('statement_or_null_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_stream_expression_1(p):
     '''stream_expression : expression '''
@@ -1740,10 +1819,10 @@ def p_streaming_concatenation_1(p):
     # { /* streaming concatenation is a SystemVerilog thing. */
     #  if (gn_system_verilog()) {
     #        yyerror(@2, "sorry: Streaming concatenation not supported.");
-    #        $$ = 0;
+    #        p[0] = None
     #  } else {
     #        yyerror(@2, "error: Streaming concatenation requires SystemVerilog");
-    #        $$ = 0;
+    #        p[0] = None
     #  }
     #       }
 ()
@@ -1951,7 +2030,7 @@ def p_tf_port_item_1(p):
     #               use_port_type = port_declaration_context.port_type;
     #  perm_string name = lex_strings.make($3);
     #  list<perm_string>* ilist = list_from_identifier($3);
-    # 
+    #
     #  if (use_port_type == NetNet::PIMPLICIT) {
     #        yyerror(@1, "error: missing task/function port direction.");
     #        use_port_type = NetNet::PINPUT; // for error recovery
@@ -1966,7 +2045,7 @@ def p_tf_port_item_1(p):
     #        tmp = pform_make_task_ports(@3, use_port_type,
     #                                    port_declaration_context.data_type,
     #                                    ilist);
-    # 
+    #
     #  } else {
     #          // Otherwise, the decorations for this identifier
     #          // indicate the type. Save the type for any right
@@ -1982,7 +2061,7 @@ def p_tf_port_item_1(p):
     #  if ($4 != 0) {
     #        pform_set_reg_idx(name, $4);
     #  }
-    # 
+    #
     #  $$ = tmp;
     #  if ($5) {
     #        assert(tmp->size()==1);
@@ -1995,7 +2074,7 @@ def p_tf_port_item_2(p):
     print('tf_port_item_2', list(p))
     # { yyerror(@3, "error: Error in task/function port item after port name %s.", $3);
     #  yyerrok;
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_tf_port_item_expr_opt_1(p):
@@ -2011,7 +2090,7 @@ def p_tf_port_item_expr_opt_1(p):
 def p_tf_port_item_expr_opt_2(p):
     '''tf_port_item_expr_opt :  '''
     print('tf_port_item_expr_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_tf_port_list_1(p):
     '''tf_port_list : _embed0_tf_port_list tf_port_item_list '''
@@ -2117,6 +2196,16 @@ def p_variable_dimension_1(p):
     #  tmp->push_back(index);
     #  $$ = tmp;
     #       }
+    # XXX TODO: subscriptlist
+    start = str(p[4])
+    end = str(p[2])
+    if end.endswith("-1"):
+        end = end[:-2]
+    elif end.isdigit():
+        end = str(int(end)+1)
+    else:
+        end = "1+%s" % end
+    p[0] = '[%s:%s]' % (start, end) # python slice is LO:HI+1
 ()
 def p_variable_dimension_2(p):
     '''variable_dimension : '[' expression ']' '''
@@ -2178,12 +2267,12 @@ def p_attribute_list_opt_1(p):
 def p_attribute_list_opt_2(p):
     '''attribute_list_opt :  '''
     print('attribute_list_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_attribute_instance_list_1(p):
     '''attribute_instance_list : K_PSTAR K_STARP '''
     print('attribute_instance_list_1', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_attribute_instance_list_2(p):
     '''attribute_instance_list : K_PSTAR attribute_list K_STARP '''
@@ -2328,12 +2417,12 @@ def p_block_item_decls_2(p):
 def p_block_item_decls_opt_1(p):
     '''block_item_decls_opt : block_item_decls '''
     print('block_item_decls_opt_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_block_item_decls_opt_2(p):
     '''block_item_decls_opt :  '''
     print('block_item_decls_opt_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_type_declaration_1(p):
     '''type_declaration : K_typedef data_type IDENTIFIER dimensions_opt ';' '''
@@ -2349,7 +2438,7 @@ def p_type_declaration_2(p):
     # { perm_string name = lex_strings.make($3.text);
     #  if (pform_test_type_identifier_local(name)) {
     #        yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text);
-    # 
+    #
     #  } else {
     #        pform_set_typedef(name, $2, NULL);
     #  }
@@ -2644,7 +2733,7 @@ def p_struct_union_member_2(p):
     print('struct_union_member_2', list(p))
     # { yyerror(@2, "Error in struct/union member.");
     #  yyerrok;
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_case_item_1(p):
@@ -2798,7 +2887,7 @@ def p_delay3_opt_1(p):
 def p_delay3_opt_2(p):
     '''delay3_opt :  '''
     print('delay3_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_delay_value_list_1(p):
     '''delay_value_list : delay_value '''
@@ -2834,7 +2923,7 @@ def p_delay_value_simple_1(p):
     # { verinum*tmp = $1;
     #            if (tmp == 0) {
     #                  yyerror(@1, "internal error: delay.");
-    #                  $$ = 0;
+    #                  p[0] = None
     #            } else {
     #                  $$ = new PENumber(tmp);
     #                  FILE_NAME($$, @1);
@@ -2848,7 +2937,7 @@ def p_delay_value_simple_2(p):
     # { verireal*tmp = $1;
     #            if (tmp == 0) {
     #                  yyerror(@1, "internal error: delay.");
-    #                  $$ = 0;
+    #                  p[0] = None
     #            } else {
     #                  $$ = new PEFNumber(tmp);
     #                  FILE_NAME($$, @1);
@@ -2868,7 +2957,7 @@ def p_delay_value_simple_4(p):
     '''delay_value_simple : TIME_LITERAL '''
     print('delay_value_simple_4', list(p))
     # { int unit;
-    # 
+    #
     #            based_size = 0;
     #            $$         = 0;
     #            if ($1 == 0 || !get_time_unit($1, unit))
@@ -2877,7 +2966,7 @@ def p_delay_value_simple_4(p):
     #                  double p = pow(10.0,
     #                                 (double)(unit - pform_get_timeunit()));
     #                  double time = atof($1) * p;
-    # 
+    #
     #                  verireal *v = new verireal(time);
     #                  $$ = new PEFNumber(v);
     #                  FILE_NAME($$, @1);
@@ -3167,7 +3256,7 @@ def p_event_control_3(p):
     '''event_control : '@' '(' error ')' '''
     print('event_control_3', list(p))
     # { yyerror(@1, "error: Malformed event control expression.");
-    #            $$ = 0;
+    #            p[0] = None
     #          }
 ()
 def p_event_expression_list_1(p):
@@ -3237,7 +3326,6 @@ def p_expression_1(p):
     '''expression : expr_primary_or_typename '''
     print('expression_1', list(p))
     p[0] = p[1]
-    p[0] = p[1]
 ()
 def p_expression_2(p):
     '''expression : inc_or_dec_expression '''
@@ -3252,7 +3340,7 @@ def p_expression_3(p):
 def p_expression_4(p):
     '''expression : '+' attribute_list_opt expr_primary %prec UNARY_PREC '''
     print('expression_4', list(p))
-    # { $$ = $3; }
+    p[0] = p[3]
 ()
 def p_expression_5(p):
     '''expression : '-' attribute_list_opt expr_primary %prec UNARY_PREC '''
@@ -3307,7 +3395,7 @@ def p_expression_11(p):
     print('expression_11', list(p))
     # { yyerror(@1, "error: '~' '&'  is not a valid expression. "
     #          "Please use operator '~&' instead.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_expression_12(p):
@@ -3315,7 +3403,7 @@ def p_expression_12(p):
     print('expression_12', list(p))
     # { yyerror(@1, "error: '~' '|'  is not a valid expression. "
     #          "Please use operator '~|' instead.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_expression_13(p):
@@ -3323,7 +3411,7 @@ def p_expression_13(p):
     print('expression_13', list(p))
     # { yyerror(@1, "error: '~' '^'  is not a valid expression. "
     #          "Please use operator '~^' instead.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_expression_14(p):
@@ -3355,7 +3443,7 @@ def p_expression_17(p):
     print('expression_17', list(p))
     # { yyerror(@1, "error: Operand of unary ! "
     #          "is not a primary expression.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_expression_18(p):
@@ -3363,7 +3451,7 @@ def p_expression_18(p):
     print('expression_18', list(p))
     # { yyerror(@1, "error: Operand of reduction ^ "
     #          "is not a primary expression.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_expression_19(p):
@@ -3421,6 +3509,7 @@ def p_expression_25(p):
     #  FILE_NAME(tmp, @2);
     #  $$ = tmp;
     #       }
+    p[0] = Node(syms.atom, [p[1], Leaf(token.MINUS, '-'), p[4]])
 ()
 def p_expression_26(p):
     '''expression : expression '&' attribute_list_opt expression '''
@@ -3726,7 +3815,7 @@ def p_expr_primary_4(p):
     '''expr_primary : TIME_LITERAL '''
     print('expr_primary_4', list(p))
     # { int unit;
-    # 
+    #
     #           based_size = 0;
     #           $$         = 0;
     #           if ($1 == 0 || !get_time_unit($1, unit))
@@ -3734,7 +3823,7 @@ def p_expr_primary_4(p):
     #           else {
     #               double p = pow(10.0, (double)(unit - pform_get_timeunit()));
     #               double time = atof($1) * p;
-    # 
+    #
     #               verireal *v = new verireal(time);
     #               $$ = new PEFNumber(v);
     #               FILE_NAME($$, @1);
@@ -4113,7 +4202,7 @@ def p_expr_primary_43(p):
     #        $$ = tmp;
     #  } else {
     #        yyerror(@1, "error: Concatenations are not allowed to be empty.");
-    #        $$ = 0;
+    #        p[0] = None
     #  }
     #       }
 ()
@@ -4171,7 +4260,7 @@ def p_function_item_list_opt_1(p):
 def p_function_item_list_opt_2(p):
     '''function_item_list_opt :  '''
     print('function_item_list_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_function_item_list_1(p):
     '''function_item_list : function_item '''
@@ -4205,7 +4294,7 @@ def p_function_item_1(p):
 def p_function_item_2(p):
     '''function_item : block_item_decl '''
     print('function_item_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_gate_instance_1(p):
     '''gate_instance : IDENTIFIER '(' expression_list_with_nuls ')' '''
@@ -4613,6 +4702,7 @@ def p_list_of_ports_2(p):
 def p_list_of_port_declarations_1(p):
     '''list_of_port_declarations : port_declaration '''
     print('list_of_port_declarations_1', list(p))
+    p[0] = [p[1]]
     # { vector<Module::port_t*>*tmp
     #                    = new vector<Module::port_t*>(1);
     #            (*tmp)[0] = $1;
@@ -4622,6 +4712,10 @@ def p_list_of_port_declarations_1(p):
 def p_list_of_port_declarations_2(p):
     '''list_of_port_declarations : list_of_port_declarations ',' port_declaration '''
     print('list_of_port_declarations_2', list(p))
+    p[1].append(Leaf(token.NEWLINE, '\n')) # should be a comma
+    # XXX p[3].prefix=' ' # add a space after the NL, must go in parameter
+    p[1].append(p[3])
+    p[0] = p[1]
     # { vector<Module::port_t*>*tmp = $1;
     #            tmp->push_back($3);
     #            $$ = tmp;
@@ -4636,7 +4730,7 @@ def p_list_of_port_declarations_3(p):
     #                                               @3.first_line);
     #            vector<Module::port_t*>*tmp = $1;
     #            tmp->push_back(ptmp);
-    # 
+    #
     #              /* Get the port declaration details, the port type
     #                 and what not, from context data stored by the
     #                 last port_declaration rule. */
@@ -4667,6 +4761,9 @@ def p_list_of_port_declarations_5(p):
 def p_port_declaration_1(p):
     '''port_declaration : attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt '''
     print('port_declaration_1', list(p))
+    # XXX TODO: python AST
+    comment, dt, name = p[2], p[4], p[5]
+    p[0] = port_decl(comment, dt, name)
     # { Module::port_t*ptmp;
     #  perm_string name = lex_strings.make($5);
     #  data_type_t*use_type = $4;
@@ -4737,6 +4834,9 @@ def p_port_declaration_4(p):
 def p_port_declaration_5(p):
     '''port_declaration : attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt '''
     print('port_declaration_5', list(p))
+    # XXX TODO: python AST
+    comment, dt, name = p[2], p[4], p[5]
+    p[0] = port_decl(comment, dt, name)
     # { Module::port_t*ptmp;
     #  perm_string name = lex_strings.make($5);
     #  data_type_t*use_dtype = $4;
@@ -4750,7 +4850,7 @@ def p_port_declaration_5(p):
     #                    use_type = NetNet::IMPLICIT;
     #              else
     #                    use_type = NetNet::IMPLICIT_REG;
-    # 
+    #
     #                // The SystemVerilog types that can show up as
     #                // output ports are implicitly (on the inside)
     #                // variables because "reg" is not valid syntax
@@ -4812,9 +4912,9 @@ def p_port_declaration_7(p):
     #  port_declaration_context.port_type = NetNet::PINOUT;
     #  port_declaration_context.port_net_type = use_type;
     #  port_declaration_context.data_type = $4;
-    # 
+    #
     #  pform_make_var_init(@5, name, $7);
-    # 
+    #
     #  delete[]$5;
     #  $$ = ptmp;
     #       }
@@ -4827,37 +4927,37 @@ def p_net_type_opt_1(p):
 def p_net_type_opt_2(p):
     '''net_type_opt :  '''
     print('net_type_opt_2', list(p))
-    # { $$ = NetNet::IMPLICIT; }
+    p[0] = NN_IMPLICIT
 ()
 def p_unsigned_signed_opt_1(p):
     '''unsigned_signed_opt : K_signed '''
     print('unsigned_signed_opt_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_unsigned_signed_opt_2(p):
     '''unsigned_signed_opt : K_unsigned '''
     print('unsigned_signed_opt_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_unsigned_signed_opt_3(p):
     '''unsigned_signed_opt :  '''
     print('unsigned_signed_opt_3', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_signed_unsigned_opt_1(p):
     '''signed_unsigned_opt : K_signed '''
     print('signed_unsigned_opt_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_signed_unsigned_opt_2(p):
     '''signed_unsigned_opt : K_unsigned '''
     print('signed_unsigned_opt_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_signed_unsigned_opt_3(p):
     '''signed_unsigned_opt :  '''
     print('signed_unsigned_opt_3', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_atom2_type_1(p):
     '''atom2_type : K_byte '''
@@ -4917,7 +5017,7 @@ def p_lpvalue_4(p):
     '''lpvalue : streaming_concatenation '''
     print('lpvalue_4', list(p))
     # { yyerror(@1, "sorry: streaming concatenation not supported in l-values.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_cont_assign_1(p):
@@ -4946,19 +5046,32 @@ def p_cont_assign_list_2(p):
 def p_module_1(p):
     '''module : attribute_list_opt module_start lifetime_opt IDENTIFIER _embed0_module module_package_import_list_opt module_parameter_port_list_opt module_port_list_opt module_attribute_foreign ';' _embed1_module timeunits_declaration_opt _embed2_module module_item_list_opt module_end _embed3_module endlabel_opt '''
     print('module_1', list(p))
+    params = p[7]
     clsname = [Leaf(token.NAME, 'class'),
                Leaf(token.NAME, p[4], prefix=' '),
                Leaf(token.COLON, ':')]
-    stmt = Node(syms.pass_stmt, [Leaf(token.NAME, "pass"),])
-    stmts = Node(syms.small_stmt, [stmt, Leaf(token.NEWLINE, '\n')])
-    stmts = Node(syms.stmt, [stmts])
+    pass_stmt = Node(syms.pass_stmt, [Leaf(token.NAME, "pass"),])
+    if params:
+        params = [Leaf(token.LPAR, '(')] + params + [Leaf(token.RPAR, ')')]
+        fn = [Leaf(token.NAME, 'def'),
+              Leaf(token.NAME, '__init__', prefix=' '),
+              Node(syms.parameters, params),
+              Leaf(token.COLON, ':')]
+        fndef = Node(syms.funcdef, fn)
+        stmts = Node(syms.stmt, [fndef])
+    else:
+        stmts = Node(syms.small_stmt, [pass_stmt, Leaf(token.NEWLINE, '\n')])
+        stmts = Node(syms.stmt, [stmts])
+
+    # XXX TODO ports as py nodes
+    ports = p[8]
+    stmts.children.append(Leaf(token.STRING, '\n' + indent(ports, 8)))
     suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
                               Leaf(token.INDENT, '    '),
                               stmts,
                               Leaf(token.DEDENT, '')
                              ])
-    clsdecl = Node(syms.classdef, clsname + [suite],
-                   prefix='', fixers_applied=[])
+    clsdecl = Node(syms.classdef, clsname + [suite])
     clsdecl = Node(syms.compound_stmt, [clsdecl])
     print ("clsdecl", repr(clsdecl))
     print ("clsstr:")
@@ -5090,17 +5203,17 @@ def p_endlabel_opt_1(p):
 def p_endlabel_opt_2(p):
     '''endlabel_opt :  '''
     print('endlabel_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_module_attribute_foreign_1(p):
     '''module_attribute_foreign : K_PSTAR IDENTIFIER K_integer IDENTIFIER '=' STRING ';' K_STARP '''
     print('module_attribute_foreign_1', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_module_attribute_foreign_2(p):
     '''module_attribute_foreign :  '''
     print('module_attribute_foreign_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_module_port_list_opt_1(p):
     '''module_port_list_opt : '(' list_of_ports ')' '''
@@ -5115,14 +5228,14 @@ def p_module_port_list_opt_2(p):
 def p_module_port_list_opt_3(p):
     '''module_port_list_opt :  '''
     print('module_port_list_opt_3', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_module_port_list_opt_4(p):
     '''module_port_list_opt : '(' error ')' '''
     print('module_port_list_opt_4', list(p))
     # { yyerror(@2, "Errors in port declarations.");
     #  yyerrok;
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_module_parameter_port_list_opt_1(p):
@@ -5132,7 +5245,7 @@ def p_module_parameter_port_list_opt_1(p):
 def p_module_parameter_port_list_opt_2(p):
     '''module_parameter_port_list_opt : '#' '(' module_parameter_port_list ')' '''
     print('module_parameter_port_list_opt_2', list(p))
-    p[0] = p[2]
+    p[0] = p[3]
 ()
 def p_module_parameter_port_list_1(p):
     '''module_parameter_port_list : K_parameter param_type parameter_assign '''
@@ -5147,6 +5260,9 @@ def p_module_parameter_port_list_2(p):
 def p_module_parameter_port_list_3(p):
     '''module_parameter_port_list : module_parameter_port_list ',' K_parameter param_type parameter_assign '''
     print('module_parameter_port_list_3', list(p))
+    p[1].append(Leaf(token.COMMA, ','))
+    p[1].append(Leaf(token.NEWLINE, '\n'))
+    p[5].prefix='                 ' # add space after newline
     p[1].append(p[5])
     p[0] = p[1]
 ()
@@ -5293,7 +5409,7 @@ def p_module_item_13(p):
     #              use_type = NetNet::REG;
     #        else
     #              use_type = NetNet::IMPLICIT_REG;
-    # 
+    #
     #          // The SystemVerilog types that can show up as
     #          // output ports are implicitly (on the inside)
     #          // variables because "reg" is not valid syntax
@@ -6010,7 +6126,7 @@ def p_parameter_value_ranges_opt_1(p):
 def p_parameter_value_ranges_opt_2(p):
     '''parameter_value_ranges_opt :  '''
     print('parameter_value_ranges_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_parameter_value_ranges_1(p):
     '''parameter_value_ranges : parameter_value_ranges parameter_value_range '''
@@ -6055,27 +6171,27 @@ def p_value_range_expression_1(p):
 def p_value_range_expression_2(p):
     '''value_range_expression : K_inf '''
     print('value_range_expression_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_value_range_expression_3(p):
     '''value_range_expression : '+' K_inf '''
     print('value_range_expression_3', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_value_range_expression_4(p):
     '''value_range_expression : '-' K_inf '''
     print('value_range_expression_4', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_from_exclude_1(p):
     '''from_exclude : K_from '''
     print('from_exclude_1', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_from_exclude_2(p):
     '''from_exclude : K_exclude '''
     print('from_exclude_2', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_parameter_value_opt_1(p):
     '''parameter_value_opt : '#' '(' expression_list_with_nuls ')' '''
@@ -6101,7 +6217,7 @@ def p_parameter_value_opt_3(p):
     # { assert($2);
     #            PENumber*tmp = new PENumber($2);
     #            FILE_NAME(tmp, @1);
-    # 
+    #
     #            struct parmvalue_t*lst = new struct parmvalue_t;
     #            lst->by_order = new list<PExpr*>;
     #            lst->by_order->push_back(tmp);
@@ -6116,7 +6232,7 @@ def p_parameter_value_opt_4(p):
     # { assert($2);
     #            PEFNumber*tmp = new PEFNumber($2);
     #            FILE_NAME(tmp, @1);
-    # 
+    #
     #            struct parmvalue_t*lst = new struct parmvalue_t;
     #            lst->by_order = new list<PExpr*>;
     #            lst->by_order->push_back(tmp);
@@ -6129,13 +6245,13 @@ def p_parameter_value_opt_5(p):
     print('parameter_value_opt_5', list(p))
     # { yyerror(@1, "error: syntax error in parameter value "
     #                    "assignment list.");
-    #            $$ = 0;
+    #            p[0] = None
     #          }
 ()
 def p_parameter_value_opt_6(p):
     '''parameter_value_opt :  '''
     print('parameter_value_opt_6', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_parameter_value_byname_1(p):
     '''parameter_value_byname : '.' IDENTIFIER '(' expression ')' '''
@@ -6214,7 +6330,7 @@ def p_port_opt_1(p):
 def p_port_opt_2(p):
     '''port_opt :  '''
     print('port_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_port_name_1(p):
     '''port_name : '.' IDENTIFIER '(' expression ')' '''
@@ -6302,20 +6418,20 @@ def p_port_reference_2(p):
     #    itmp.sel = index_component_t::SEL_PART;
     #    itmp.msb = $3;
     #    itmp.lsb = $5;
-    # 
+    #
     #    name_component_t ntmp (lex_strings.make($1));
     #    ntmp.index.push_back(itmp);
-    # 
+    #
     #    pform_name_t pname;
     #    pname.push_back(ntmp);
-    # 
+    #
     #    PEIdent*wtmp = new PEIdent(pname);
     #    FILE_NAME(wtmp, @1);
-    # 
+    #
     #    Module::port_t*ptmp = new Module::port_t;
     #    ptmp->name = perm_string();
     #    ptmp->expr.push_back(wtmp);
-    # 
+    #
     #    delete[]$1;
     #    $$ = ptmp;
     #  }
@@ -6327,16 +6443,16 @@ def p_port_reference_3(p):
     #    itmp.sel = index_component_t::SEL_BIT;
     #    itmp.msb = $3;
     #    itmp.lsb = 0;
-    # 
+    #
     #    name_component_t ntmp (lex_strings.make($1));
     #    ntmp.index.push_back(itmp);
-    # 
+    #
     #    pform_name_t pname;
     #    pname.push_back(ntmp);
-    # 
+    #
     #    PEIdent*tmp = new PEIdent(pname);
     #    FILE_NAME(tmp, @1);
-    # 
+    #
     #    Module::port_t*ptmp = new Module::port_t;
     #    ptmp->name = perm_string();
     #    ptmp->expr.push_back(tmp);
@@ -6374,7 +6490,7 @@ def p_port_reference_list_2(p):
 def p_dimensions_opt_1(p):
     '''dimensions_opt :  '''
     print('dimensions_opt_1', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_dimensions_opt_2(p):
     '''dimensions_opt : dimensions '''
@@ -6688,12 +6804,12 @@ def p_specify_edge_path_decl_2(p):
 def p_edge_operator_1(p):
     '''edge_operator : K_posedge '''
     print('edge_operator_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_edge_operator_2(p):
     '''edge_operator : K_negedge '''
     print('edge_operator_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_specify_edge_path_1(p):
     '''specify_edge_path : '(' specify_path_identifiers spec_polarity K_EG '(' specify_path_identifiers polarity_operator expression ')' ')' '''
@@ -6749,7 +6865,7 @@ def p_specify_simple_path_decl_3(p):
     print('specify_simple_path_decl_3', list(p))
     # { yyerror(@3, "Syntax error in delay value list.");
     #            yyerrok;
-    #            $$ = 0;
+    #            p[0] = None
     #          }
 ()
 def p_specify_simple_path_1(p):
@@ -6943,7 +7059,7 @@ def p_spec_polarity_2(p):
 def p_spec_polarity_3(p):
     '''spec_polarity :  '''
     print('spec_polarity_3', list(p))
-    # { $$ = 0;   }
+    # { p[0] = None   }
 ()
 def p_spec_reference_event_1(p):
     '''spec_reference_event : K_posedge expression '''
@@ -7312,7 +7428,7 @@ def p_statement_item_30(p):
     # { PEventStatement*tmp = $1;
     #  if (tmp == 0) {
     #        yyerror(@1, "error: Invalid event control.");
-    #        $$ = 0;
+    #        p[0] = None
     #  } else {
     #        tmp->set_statement($2);
     #        $$ = tmp;
@@ -7723,7 +7839,7 @@ def p_statement_or_null_list_opt_1(p):
 def p_statement_or_null_list_opt_2(p):
     '''statement_or_null_list_opt :  '''
     print('statement_or_null_list_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_statement_or_null_list_1(p):
     '''statement_or_null_list : statement_or_null_list statement_or_null '''
@@ -7781,7 +7897,7 @@ def p_task_item_list_opt_1(p):
 def p_task_item_list_opt_2(p):
     '''task_item_list_opt :  '''
     print('task_item_list_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_tf_port_list_opt_1(p):
     '''tf_port_list_opt : tf_port_list '''
@@ -7791,7 +7907,7 @@ def p_tf_port_list_opt_1(p):
 def p_tf_port_list_opt_2(p):
     '''tf_port_list_opt :  '''
     print('tf_port_list_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_udp_body_1(p):
     '''udp_body : K_table udp_entry_list K_endtable '''
@@ -7805,7 +7921,7 @@ def p_udp_body_2(p):
     print('udp_body_2', list(p))
     # { lex_end_table();
     #  yyerror(@1, "error: Empty UDP table.");
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_udp_body_3(p):
@@ -7814,7 +7930,7 @@ def p_udp_body_3(p):
     # { lex_end_table();
     #  yyerror(@2, "Errors in UDP table");
     #  yyerrok;
-    #  $$ = 0;
+    #  p[0] = None
     #       }
 ()
 def p_udp_entry_list_1(p):
@@ -7907,7 +8023,7 @@ def p_udp_init_opt_1(p):
 def p_udp_init_opt_2(p):
     '''udp_init_opt :  '''
     print('udp_init_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_udp_input_list_1(p):
     '''udp_input_list : udp_input_sym '''
@@ -8151,12 +8267,12 @@ def p_udp_port_list_2(p):
 def p_udp_reg_opt_1(p):
     '''udp_reg_opt : K_reg '''
     print('udp_reg_opt_1', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_udp_reg_opt_2(p):
     '''udp_reg_opt :  '''
     print('udp_reg_opt_2', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_udp_initial_expr_opt_1(p):
     '''udp_initial_expr_opt : '=' expression '''
@@ -8166,7 +8282,7 @@ def p_udp_initial_expr_opt_1(p):
 def p_udp_initial_expr_opt_2(p):
     '''udp_initial_expr_opt :  '''
     print('udp_initial_expr_opt_2', list(p))
-    # { $$ = 0; }
+    # { p[0] = None }
 ()
 def p_udp_input_declaration_list_1(p):
     '''udp_input_declaration_list : K_input IDENTIFIER '''
@@ -8231,43 +8347,43 @@ def p_udp_primitive_2(p):
 def p_K_packed_opt_1(p):
     '''K_packed_opt : K_packed '''
     print('K_packed_opt', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_K_packed_opt_2(p):
     '''K_packed_opt :  '''
     print('K_packed_opt', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_K_reg_opt_1(p):
     '''K_reg_opt : K_reg '''
     print('K_reg_opt', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_K_reg_opt_2(p):
     '''K_reg_opt :  '''
     print('K_reg_opt', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 def p_K_static_opt_1(p):
     '''K_static_opt : K_static '''
     print('K_static_opt', list(p))
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_K_static_opt_2(p):
     '''K_static_opt :  '''
     print('K_static_opt', list(p))
-    # { $$ = false; }
+    p[0] = False
 ()
 
 def p_K_virtual_opt_1(p):
     '''K_virtual_opt : K_virtual '''
     print(p)
-    # { $$ = true; }
+    p[0] = True
 ()
 def p_K_virtual_opt_2(p):
     '''K_virtual_opt :  '''
     print(p)
-    # { $$ = false; }
+    p[0] = False
 ()
 
 def p_error(p):