"""
   Copyright 2013, Shinya Takamaeda-Yamazaki and Contributors

   Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0

   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.
"""

from __future__ import absolute_import
from __future__ import print_function
import sys
import os
import pathlib
from ply.yacc import yacc

from pyverilog.vparser.preprocessor import VerilogPreprocessor
from pyverilog.vparser.lexer import VerilogLexer
from pyverilog.vparser.ast import *


class VerilogParser(object):
    'Verilog HDL Parser'

    # Expression Precedence
    # Reference: http://hp.vector.co.jp/authors/VA016670/verilog/index.html
    precedence = (
        # <- Weak
        ('left', 'LOR'),
        ('left', 'LAND'),
        ('left', 'OR'),
        ('left', 'XOR', 'XNOR'),
        ('left', 'AND'),
        ('left', 'EQ', 'NE', 'EQL', 'NEL'),
        ('left', 'LT', 'GT', 'LE', 'GE'),
        ('left', 'LSHIFT', 'RSHIFT', 'LSHIFTA', 'RSHIFTA'),
        ('left', 'PLUS', 'MINUS'),
        ('left', 'TIMES', 'DIVIDE', 'MOD'),
        ('left', 'POWER'),
        ('right', 'UMINUS', 'UPLUS', 'ULNOT', 'UNOT',
         'UAND', 'UNAND', 'UOR', 'UNOR', 'UXOR', 'UXNOR'),
        # -> Strong
    )

    def __init__(self, outputdir=".", debug=True):
        self.lexer = VerilogLexer(error_func=self._lexer_error_func)
        self.lexer.build()

        self.tokens = self.lexer.tokens
        pathlib.Path(outputdir).mkdir(parents=True, exist_ok=True)
        self.parser = yacc(
            module=self,
            method="LALR",
            outputdir=outputdir,
            debug=debug
        )

    def _lexer_error_func(self, msg, line, column):
        coord = self._coord(line, column)
        raise ParseError('%s: %s' % (coord, msg))

    def get_directives(self):
        return self.lexer.get_directives()

    def get_default_nettype(self):
        return self.lexer.get_default_nettype()

    # Returns AST
    def parse(self, text, debug=0):
        return self.parser.parse(text, lexer=self.lexer, debug=debug)

    # --------------------------------------------------------------------------
    # Parse Rule Definition
    # --------------------------------------------------------------------------
    def p_source_text(self, p):
        'source_text : description'
        p[0] = Source(name='', description=p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_description(self, p):
        'description : definitions'
        p[0] = Description(definitions=p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_definitions(self, p):
        'definitions : definitions definition'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_definitions_one(self, p):
        'definitions : definition'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_definition(self, p):
        'definition : moduledef'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_definition_pragma(self, p):
        'definition : pragma'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_pragma_assign(self, p):
        'pragma : LPAREN TIMES ID EQUALS expression TIMES RPAREN'
        p[0] = Pragma(PragmaEntry(p[3], p[5], lineno=p.lineno(1)),
                      lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_pragma(self, p):
        'pragma : LPAREN TIMES ID TIMES RPAREN'
        p[0] = Pragma(PragmaEntry(p[3], lineno=p.lineno(1)),
                      lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_moduledef(self, p):
        'moduledef : MODULE modulename paramlist portlist items ENDMODULE'
        p[0] = ModuleDef(name=p[2], paramlist=p[3], portlist=p[4], items=p[5],
                         default_nettype=self.get_default_nettype(), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(6)

    def p_modulename(self, p):
        'modulename : ID'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_modulename_or(self, p):
        'modulename : SENS_OR'  # or primitive
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_paramlist(self, p):
        'paramlist : DELAY LPAREN params RPAREN'
        p[0] = Paramlist(params=p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_paramlist_empty(self, p):
        'paramlist : empty'
        p[0] = Paramlist(params=())

    def p_params(self, p):
        'params : params_begin param_end'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_params_begin(self, p):
        'params_begin : params_begin param'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_params_begin_one(self, p):
        'params_begin : param'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_params_one(self, p):
        'params : param_end'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_param(self, p):
        'param : PARAMETER param_substitution_list COMMA'
        paramlist = [Parameter(rname, rvalue, lineno=p.lineno(2))
                     for rname, rvalue in p[2]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_signed(self, p):
        'param : PARAMETER SIGNED param_substitution_list COMMA'
        paramlist = [Parameter(rname, rvalue, signed=True, lineno=p.lineno(2))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_width(self, p):
        'param : PARAMETER width param_substitution_list COMMA'
        paramlist = [Parameter(rname, rvalue, p[2], lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_signed_width(self, p):
        'param : PARAMETER SIGNED width param_substitution_list COMMA'
        paramlist = [Parameter(rname, rvalue, p[3], signed=True, lineno=p.lineno(3))
                     for rname, rvalue in p[4]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_integer(self, p):
        'param : PARAMETER INTEGER param_substitution_list COMMA'
        paramlist = [Parameter(rname, rvalue, lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_end(self, p):
        'param_end : PARAMETER param_substitution_list'
        paramlist = [Parameter(rname, rvalue, lineno=p.lineno(2))
                     for rname, rvalue in p[2]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_end_signed(self, p):
        'param_end : PARAMETER SIGNED param_substitution_list'
        paramlist = [Parameter(rname, rvalue, signed=True, lineno=p.lineno(2))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_end_width(self, p):
        'param_end : PARAMETER width param_substitution_list'
        paramlist = [Parameter(rname, rvalue, p[2], lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_end_signed_width(self, p):
        'param_end : PARAMETER SIGNED width param_substitution_list'
        paramlist = [Parameter(rname, rvalue, p[3], signed=True, lineno=p.lineno(3))
                     for rname, rvalue in p[4]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_end_integer(self, p):
        'param_end : PARAMETER INTEGER param_substitution_list'
        paramlist = [Parameter(rname, rvalue, lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_portlist(self, p):
        'portlist : LPAREN ports RPAREN SEMICOLON'
        p[0] = Portlist(ports=p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_portlist_io(self, p):
        'portlist : LPAREN ioports RPAREN SEMICOLON'
        p[0] = Portlist(ports=p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_portlist_paren_empty(self, p):
        'portlist : LPAREN RPAREN SEMICOLON'
        p[0] = Portlist(ports=(), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_portlist_empty(self, p):
        'portlist : SEMICOLON'
        p[0] = Portlist(ports=(), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_ports(self, p):
        'ports : ports COMMA portname'
        port = Port(name=p[3], width=None, dimensions=None, type=None, lineno=p.lineno(1))
        p[0] = p[1] + (port,)
        p.set_lineno(0, p.lineno(1))

    def p_ports_one(self, p):
        'ports : portname'
        port = Port(name=p[1], width=None, dimensions=None, type=None, lineno=p.lineno(1))
        p[0] = (port,)
        p.set_lineno(0, p.lineno(1))

    def p_portname(self, p):
        'portname : ID'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtypes(self, p):
        'sigtypes : sigtypes sigtype'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_sigtypes_one(self, p):
        'sigtypes : sigtype'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_input(self, p):
        'sigtype : INPUT'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_output(self, p):
        'sigtype : OUTPUT'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_inout(self, p):
        'sigtype : INOUT'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_tri(self, p):
        'sigtype : TRI'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_reg(self, p):
        'sigtype : REG'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_logic(self, p):
        'sigtype : LOGIC'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_wire(self, p):
        'sigtype : WIRE'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_signed(self, p):
        'sigtype : SIGNED'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_supply0(self, p):
        'sigtype : SUPPLY0'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_sigtype_supply1(self, p):
        'sigtype : SUPPLY1'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_ioports(self, p):
        'ioports : ioports COMMA ioport'
        if isinstance(p[3], str):
            t = None
            for r in reversed(p[1]):
                if isinstance(r.first, Input):
                    t = Ioport(Input(name=p[3], width=r.first.width, lineno=p.lineno(3)),
                               lineno=p.lineno(3))
                    break
                if isinstance(r.first, Output) and r.second is None:
                    t = Ioport(Output(name=p[3], width=r.first.width, lineno=p.lineno(3)),
                               lineno=p.lineno(3))
                    break
                if isinstance(r.first, Output) and isinstance(r.second, Reg):
                    t = Ioport(Output(name=p[3], width=r.first.width, lineno=p.lineno(3)),
                               Reg(name=p[3], width=r.first.width,
                                   lineno=p.lineno(3)),
                               lineno=p.lineno(3))
                    break
                if isinstance(r.first, Inout):
                    t = Ioport(Inout(name=p[3], width=r.first.width, lineno=p.lineno(3)),
                               lineno=p.lineno(3))
                    break
            p[0] = p[1] + (t,)
        else:
            p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_ioports_one(self, p):
        'ioports : ioport_head'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def create_ioport(self, sigtypes, name, width=None, dimensions=None, lineno=0):
        self.typecheck_ioport(sigtypes)
        first = None
        second = None
        signed = False
        if 'signed' in sigtypes:
            signed = True
        if 'input' in sigtypes:
            first = Input(name=name, width=width, signed=signed,
                          dimensions=dimensions, lineno=lineno)
        if 'output' in sigtypes:
            first = Output(name=name, width=width, signed=signed,
                           dimensions=dimensions, lineno=lineno)
        if 'inout' in sigtypes:
            first = Inout(name=name, width=width, signed=signed,
                          dimensions=dimensions, lineno=lineno)
        if 'wire' in sigtypes:
            second = Wire(name=name, width=width, signed=signed,
                          dimensions=dimensions, lineno=lineno)
        if 'reg' in sigtypes:
            second = Reg(name=name, width=width, signed=signed,
                         dimensions=dimensions, lineno=lineno)
        if 'tri' in sigtypes:
            second = Tri(name=name, width=width, signed=signed,
                         dimensions=dimensions, lineno=lineno)
        return Ioport(first, second, lineno=lineno)

    def typecheck_ioport(self, sigtypes):
        if 'input' not in sigtypes and 'output' not in sigtypes and 'inout' not in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'output' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'output' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'input' in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'reg' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'reg' in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'tri' in sigtypes:
            raise ParseError("Syntax Error")
        if 'output' in sigtypes and 'tri' in sigtypes:
            raise ParseError("Syntax Error")

    def p_ioport(self, p):
        'ioport : sigtypes portname'
        p[0] = self.create_ioport(p[1], p[2], lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(1))

    def p_ioport_width(self, p):
        'ioport : sigtypes width portname'
        p[0] = self.create_ioport(p[1], p[3], width=p[2], lineno=p.lineno(3))
        p.set_lineno(0, p.lineno(1))

    def p_ioport_dimensions(self, p):
        'ioport : sigtypes width portname dimensions'
        p[0] = self.create_ioport(p[1], p[3], width=p[2], dimensions=p[4], lineno=p.lineno(3))
        p.set_lineno(0, p.lineno(1))

    def p_ioport_head(self, p):
        'ioport_head : sigtypes portname'
        p[0] = self.create_ioport(p[1], p[2], lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(1))

    def p_ioport_head_width(self, p):
        'ioport_head : sigtypes width portname'
        p[0] = self.create_ioport(p[1], p[3], width=p[2], lineno=p.lineno(3))
        p.set_lineno(0, p.lineno(1))

    def p_ioport_head_dimensions(self, p):
        'ioport_head : sigtypes width portname dimensions'
        p[0] = self.create_ioport(p[1], p[3], width=p[2], dimensions=p[4], lineno=p.lineno(3))
        p.set_lineno(0, p.lineno(1))

    def p_ioport_portname(self, p):
        'ioport : portname'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_width(self, p):
        'width : LBRACKET expression COLON expression RBRACKET'
        p[0] = Width(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_length(self, p):
        'length : LBRACKET expression COLON expression RBRACKET'
        p[0] = Length(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_dimensions(self, p):
        'dimensions : dimensions length'
        dims = p[1].lengths + [p[2]]
        p[0] = Dimensions(dims, lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_dimensions_one(self, p):
        'dimensions : length'
        dims = [p[1]]
        p[0] = Dimensions(dims, lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_items(self, p):
        'items : items item'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_items_one(self, p):
        'items : item'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_items_empty(self, p):
        'items : empty'
        p[0] = ()

    def p_item(self, p):
        """item : standard_item
        | generate
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_standard_item(self, p):
        """standard_item : decl
        | integerdecl
        | realdecl
        | declassign
        | parameterdecl
        | localparamdecl
        | genvardecl
        | assignment
        | always
        | always_ff
        | always_comb
        | always_latch
        | initial
        | instance
        | function
        | task
        | pragma
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # Signal Decl
    def create_decl(self, sigtypes, name, width=None, dimensions=None, lineno=0):
        self.typecheck_decl(sigtypes, dimensions)
        decls = []
        signed = False
        if 'signed' in sigtypes:
            signed = True
        if 'input' in sigtypes:
            decls.append(Input(name=name, width=width,
                               signed=signed, lineno=lineno, dimensions=dimensions))
        if 'output' in sigtypes:
            decls.append(Output(name=name, width=width,
                                signed=signed, lineno=lineno, dimensions=dimensions))
        if 'inout' in sigtypes:
            decls.append(Inout(name=name, width=width,
                               signed=signed, lineno=lineno, dimensions=dimensions))
        if 'wire' in sigtypes:
            decls.append(Wire(name=name, width=width,
                              signed=signed, lineno=lineno, dimensions=dimensions))
        if 'reg' in sigtypes:
            decls.append(Reg(name=name, width=width,
                             signed=signed, lineno=lineno, dimensions=dimensions))
        if 'tri' in sigtypes:
            decls.append(Tri(name=name, width=width,
                             signed=signed, lineno=lineno, dimensions=dimensions))
        if 'supply0' in sigtypes:
            decls.append(Supply(name=name, value=IntConst('0', lineno=lineno),
                                width=width, signed=signed, lineno=lineno))
        if 'supply1' in sigtypes:
            decls.append(Supply(name=name, value=IntConst('1', lineno=lineno),
                                width=width, signed=signed, lineno=lineno))
        return decls

    def typecheck_decl(self, sigtypes, dimensions=None):
        if ('supply0' in sigtypes or 'supply1' in sigtypes) and \
           dimensions is not None:
            raise ParseError("SyntaxError")
        if len(sigtypes) == 1 and 'signed' in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'output' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'output' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'input' in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'reg' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'reg' in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'tri' in sigtypes:
            raise ParseError("Syntax Error")
        if 'output' in sigtypes and 'tri' in sigtypes:
            raise ParseError("Syntax Error")

    def p_decl(self, p):
        'decl : sigtypes declnamelist SEMICOLON'
        decllist = []
        for rname, rdimensions in p[2]:
            decllist.extend(self.create_decl(p[1], rname, dimensions=rdimensions,
                                             lineno=p.lineno(2)))
        p[0] = Decl(tuple(decllist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_decl_width(self, p):
        'decl : sigtypes width declnamelist SEMICOLON'
        decllist = []
        for rname, rdimensions in p[3]:
            decllist.extend(self.create_decl(p[1], rname, width=p[2], dimensions=rdimensions,
                                             lineno=p.lineno(3)))
        p[0] = Decl(tuple(decllist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_declnamelist(self, p):
        'declnamelist : declnamelist COMMA declname'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_declnamelist_one(self, p):
        'declnamelist : declname'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_declname(self, p):
        'declname : ID'
        p[0] = (p[1], None)
        p.set_lineno(0, p.lineno(1))

    def p_declarray(self, p):
        'declname : ID dimensions'
        p[0] = (p[1], p[2])
        p.set_lineno(0, p.lineno(1))

    # Decl and Assign
    def create_declassign(self, sigtypes, name, assign, width=None, lineno=0):
        self.typecheck_declassign(sigtypes)
        decls = []
        signed = False
        if 'signed' in sigtypes:
            signed = True
        if 'input' in sigtypes:
            decls.append(Input(name=name, width=width,
                               signed=signed, lineno=lineno))
        if 'output' in sigtypes:
            decls.append(Output(name=name, width=width,
                                signed=signed, lineno=lineno))
        if 'inout' in sigtypes:
            decls.append(Inout(name=name, width=width,
                               signed=signed, lineno=lineno))
        if 'wire' in sigtypes:
            decls.append(Wire(name=name, width=width,
                              signed=signed, lineno=lineno))
        if 'reg' in sigtypes:
            decls.append(Reg(name=name, width=width,
                             signed=signed, lineno=lineno))
        decls.append(assign)
        return decls

    def typecheck_declassign(self, sigtypes):
        if len(sigtypes) == 1 and 'signed' in sigtypes:
            raise ParseError("Syntax Error")
        if 'reg' not in sigtypes and 'wire' not in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'output' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'output' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'input' in sigtypes:
            raise ParseError("Syntax Error")
        if 'input' in sigtypes and 'reg' in sigtypes:
            raise ParseError("Syntax Error")
        if 'inout' in sigtypes and 'reg' in sigtypes:
            raise ParseError("Syntax Error")
        if 'supply0' in sigtypes and len(sigtypes) != 1:
            raise ParseError("Syntax Error")
        if 'supply1' in sigtypes and len(sigtypes) != 1:
            raise ParseError("Syntax Error")

    def p_declassign(self, p):
        'declassign : sigtypes declassign_element SEMICOLON'
        decllist = self.create_declassign(
            p[1], p[2][0], p[2][1], lineno=p.lineno(2))
        p[0] = Decl(decllist, lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_declassign_width(self, p):
        'declassign : sigtypes width declassign_element SEMICOLON'
        decllist = self.create_declassign(
            p[1], p[3][0], p[3][1], width=p[2], lineno=p.lineno(3))
        p[0] = Decl(tuple(decllist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_declassign_element(self, p):
        'declassign_element : ID EQUALS rvalue'
        assign = Assign(Lvalue(Identifier(p[1], lineno=p.lineno(1)), lineno=p.lineno(1)),
                        p[3], lineno=p.lineno(1))
        p[0] = (p[1], assign)
        p.set_lineno(0, p.lineno(1))

    def p_declassign_element_delay(self, p):
        'declassign_element : delays ID EQUALS delays rvalue'
        assign = Assign(Lvalue(Identifier(p[2], lineno=p.lineno(1)), lineno=p.lineno(2)),
                        p[5], p[1], p[4], lineno=p.lineno(2))
        p[0] = (p[1], assign)
        p.set_lineno(0, p.lineno(2))

    # Integer
    def p_integerdecl(self, p):
        'integerdecl : INTEGER integernamelist SEMICOLON'
        intlist = [Integer(rname,
                           Width(msb=IntConst('31', lineno=p.lineno(2)),
                                 lsb=IntConst('0', lineno=p.lineno(2)),
                                 lineno=p.lineno(2)),
                           signed=True,
                           value=rvalue,
                           lineno=p.lineno(2)) for rname, rvalue in p[2]]
        p[0] = Decl(tuple(intlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_integerdecl_signed(self, p):
        'integerdecl : INTEGER SIGNED integernamelist SEMICOLON'
        intlist = [Integer(rname,
                           Width(msb=IntConst('31', lineno=p.lineno(3)),
                                 lsb=IntConst('0', lineno=p.lineno(3)),
                                 lineno=p.lineno(3)),
                           signed=True,
                           value=rvalue,
                           lineno=p.lineno(3)) for rname, rvalue in p[2]]
        p[0] = Decl(tuple(intlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_integernamelist(self, p):
        'integernamelist : integernamelist COMMA integername'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_integernamelist_one(self, p):
        'integernamelist : integername'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_integername_init(self, p):
        'integername : ID EQUALS rvalue'
        p[0] = (p[1], p[3])
        p.set_lineno(0, p.lineno(1))

    def p_integername(self, p):
        'integername : ID'
        p[0] = (p[1], None)
        p.set_lineno(0, p.lineno(1))

    # Real
    def p_realdecl(self, p):
        'realdecl : REAL realnamelist SEMICOLON'
        reallist = [Real(p[1],
                         Width(msb=IntConst('31', lineno=p.lineno(2)),
                               lsb=IntConst('0', lineno=p.lineno(2)),
                               lineno=p.lineno(2)),
                         lineno=p.lineno(2)) for r in p[2]]
        p[0] = Decl(tuple(reallist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_realnamelist(self, p):
        'realnamelist : realnamelist COMMA realname'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_realnamelist_one(self, p):
        'realnamelist : realname'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_realname(self, p):
        'realname : ID'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # Parameter
    def p_parameterdecl(self, p):
        'parameterdecl : PARAMETER param_substitution_list SEMICOLON'
        paramlist = [Parameter(rname, rvalue, lineno=p.lineno(2))
                     for rname, rvalue in p[2]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_parameterdecl_signed(self, p):
        'parameterdecl : PARAMETER SIGNED param_substitution_list SEMICOLON'
        paramlist = [Parameter(rname, rvalue, signed=True, lineno=p.lineno(2))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_parameterdecl_width(self, p):
        'parameterdecl : PARAMETER width param_substitution_list SEMICOLON'
        paramlist = [Parameter(rname, rvalue, p[2], lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_parameterdecl_signed_width(self, p):
        'parameterdecl : PARAMETER SIGNED width param_substitution_list SEMICOLON'
        paramlist = [Parameter(rname, rvalue, p[3], signed=True, lineno=p.lineno(3))
                     for rname, rvalue in p[4]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_parameterdecl_integer(self, p):
        'parameterdecl : PARAMETER INTEGER param_substitution_list SEMICOLON'
        paramlist = [Parameter(rname, rvalue, lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_localparamdecl(self, p):
        'localparamdecl : LOCALPARAM param_substitution_list SEMICOLON'
        paramlist = [Localparam(rname, rvalue, lineno=p.lineno(2))
                     for rname, rvalue in p[2]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_localparamdecl_signed(self, p):
        'localparamdecl : LOCALPARAM SIGNED param_substitution_list SEMICOLON'
        paramlist = [Localparam(rname, rvalue, signed=True, lineno=p.lineno(2))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_localparamdecl_width(self, p):
        'localparamdecl : LOCALPARAM width param_substitution_list SEMICOLON'
        paramlist = [Localparam(rname, rvalue, p[2], lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_localparamdecl_signed_width(self, p):
        'localparamdecl : LOCALPARAM SIGNED width param_substitution_list SEMICOLON'
        paramlist = [Localparam(rname, rvalue, p[3], signed=True, lineno=p.lineno(3))
                     for rname, rvalue in p[4]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_localparamdecl_integer(self, p):
        'localparamdecl : LOCALPARAM INTEGER param_substitution_list SEMICOLON'
        paramlist = [Localparam(rname, rvalue, lineno=p.lineno(3))
                     for rname, rvalue in p[3]]
        p[0] = Decl(tuple(paramlist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_substitution_list(self, p):
        'param_substitution_list : param_substitution_list COMMA param_substitution'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_param_substitution_list_one(self, p):
        'param_substitution_list : param_substitution'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_param_substitution(self, p):
        'param_substitution : ID EQUALS rvalue'
        p[0] = (p[1], p[3])
        p.set_lineno(0, p.lineno(1))

    def p_assignment(self, p):
        'assignment : ASSIGN lvalue EQUALS rvalue SEMICOLON'
        p[0] = Assign(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(5)

    def p_assignment_delay(self, p):
        'assignment : ASSIGN delays lvalue EQUALS delays rvalue SEMICOLON'
        p[0] = Assign(p[3], p[6], p[2], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(7)

    # --------------------------------------------------------------------------
    def p_lpartselect_lpointer(self, p):
        'lpartselect : pointer LBRACKET expression COLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lpartselect_lpointer_plus(self, p):
        'lpartselect : pointer LBRACKET expression PLUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Plus(p[3], p[5]), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lpartselect_lpointer_minus(self, p):
        'lpartselect : pointer LBRACKET expression MINUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Minus(p[3], p[5]), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lpartselect(self, p):
        'lpartselect : identifier LBRACKET expression COLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lpartselect_plus(self, p):
        'lpartselect : identifier LBRACKET expression PLUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Plus(p[3], p[5]), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lpartselect_minus(self, p):
        'lpartselect : identifier LBRACKET expression MINUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Minus(p[3], p[5]), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lpointer(self, p):
        'lpointer : pointer'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_lconcat(self, p):
        'lconcat : LBRACE lconcatlist RBRACE'
        p[0] = LConcat(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lconcatlist(self, p):
        'lconcatlist : lconcatlist COMMA lconcat_one'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_lconcatlist_one(self, p):
        'lconcatlist : lconcat_one'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_lconcat_one_identifier(self, p):
        'lconcat_one : identifier'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_lconcat_one_lpartselect(self, p):
        'lconcat_one : lpartselect'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_lconcat_one_lpointer(self, p):
        'lconcat_one : lpointer'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_lconcat_one_lconcat(self, p):
        'lconcat_one : lconcat'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_lvalue_partselect(self, p):
        'lvalue : lpartselect'
        p[0] = Lvalue(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lvalue_pointer(self, p):
        'lvalue : lpointer'
        p[0] = Lvalue(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lvalue_concat(self, p):
        'lvalue : lconcat'
        p[0] = Lvalue(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_lvalue_one(self, p):
        'lvalue : identifier'
        p[0] = Lvalue(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_rvalue(self, p):
        'rvalue : expression'
        p[0] = Rvalue(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 1 (Highest Priority)
    def p_expression_uminus(self, p):
        'expression : MINUS expression %prec UMINUS'
        p[0] = Uminus(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_uplus(self, p):
        'expression : PLUS expression %prec UPLUS'
        p[0] = p[2]
        p.set_lineno(0, p.lineno(1))

    def p_expression_ulnot(self, p):
        'expression : LNOT expression %prec ULNOT'
        p[0] = Ulnot(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_unot(self, p):
        'expression : NOT expression %prec UNOT'
        p[0] = Unot(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_uand(self, p):
        'expression : AND expression %prec UAND'
        p[0] = Uand(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_unand(self, p):
        'expression : NAND expression %prec UNAND'
        p[0] = Unand(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_unor(self, p):
        'expression : NOR expression %prec UNOR'
        p[0] = Unor(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_uor(self, p):
        'expression : OR expression %prec UOR'
        p[0] = Uor(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_uxor(self, p):
        'expression : XOR expression %prec UXOR'
        p[0] = Uxor(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_uxnor(self, p):
        'expression : XNOR expression %prec UXNOR'
        p[0] = Uxnor(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 2
    def p_expression_power(self, p):
        'expression : expression POWER expression'
        p[0] = Power(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 3
    def p_expression_times(self, p):
        'expression : expression TIMES expression'
        p[0] = Times(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_div(self, p):
        'expression : expression DIVIDE expression'
        p[0] = Divide(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_mod(self, p):
        'expression : expression MOD expression'
        p[0] = Mod(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 4
    def p_expression_plus(self, p):
        'expression : expression PLUS expression'
        p[0] = Plus(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_minus(self, p):
        'expression : expression MINUS expression'
        p[0] = Minus(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 5
    def p_expression_sll(self, p):
        'expression : expression LSHIFT expression'
        p[0] = Sll(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_srl(self, p):
        'expression : expression RSHIFT expression'
        p[0] = Srl(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_sla(self, p):
        'expression : expression LSHIFTA expression'
        p[0] = Sla(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_sra(self, p):
        'expression : expression RSHIFTA expression'
        p[0] = Sra(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 6
    def p_expression_lessthan(self, p):
        'expression : expression LT expression'
        p[0] = LessThan(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_greaterthan(self, p):
        'expression : expression GT expression'
        p[0] = GreaterThan(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_lesseq(self, p):
        'expression : expression LE expression'
        p[0] = LessEq(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_greatereq(self, p):
        'expression : expression GE expression'
        p[0] = GreaterEq(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 7
    def p_expression_eq(self, p):
        'expression : expression EQ expression'
        p[0] = Eq(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_noteq(self, p):
        'expression : expression NE expression'
        p[0] = NotEq(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_eql(self, p):
        'expression : expression EQL expression'
        p[0] = Eql(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_noteql(self, p):
        'expression : expression NEL expression'
        p[0] = NotEql(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 8
    def p_expression_And(self, p):
        'expression : expression AND expression'
        p[0] = And(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_Xor(self, p):
        'expression : expression XOR expression'
        p[0] = Xor(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_expression_Xnor(self, p):
        'expression : expression XNOR expression'
        p[0] = Xnor(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 9
    def p_expression_Or(self, p):
        'expression : expression OR expression'
        p[0] = Or(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 10
    def p_expression_land(self, p):
        'expression : expression LAND expression'
        p[0] = Land(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 11
    def p_expression_lor(self, p):
        'expression : expression LOR expression'
        p[0] = Lor(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Level 12
    def p_expression_cond(self, p):
        'expression : expression COND expression COLON expression'
        p[0] = Cond(p[1], p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_expression_expr(self, p):
        'expression : LPAREN expression RPAREN'
        p[0] = p[2]
        p.set_lineno(0, p.lineno(2))

    # --------------------------------------------------------------------------
    def p_expression_concat(self, p):
        'expression : concat'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_repeat(self, p):
        'expression : repeat'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_partselect(self, p):
        'expression : partselect'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_pointer(self, p):
        'expression : pointer'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_functioncall(self, p):
        'expression : functioncall'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_systemcall(self, p):
        'expression : systemcall'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_id(self, p):
        'expression : identifier'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_expression_const(self, p):
        'expression : const_expression'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_concat(self, p):
        'concat : LBRACE concatlist RBRACE'
        p[0] = Concat(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_concatlist(self, p):
        'concatlist : concatlist COMMA expression'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_concatlist_one(self, p):
        'concatlist : expression'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_repeat(self, p):
        'repeat : LBRACE expression concat RBRACE'
        p[0] = Repeat(p[3], p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_partselect(self, p):
        'partselect : identifier LBRACKET expression COLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_partselect_plus(self, p):
        'partselect : identifier LBRACKET expression PLUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Plus(
            p[3], p[5], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_partselect_minus(self, p):
        'partselect : identifier LBRACKET expression MINUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Minus(
            p[3], p[5], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_partselect_pointer(self, p):
        'partselect : pointer LBRACKET expression COLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_partselect_pointer_plus(self, p):
        'partselect : pointer LBRACKET expression PLUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Plus(
            p[3], p[5], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_partselect_pointer_minus(self, p):
        'partselect : pointer LBRACKET expression MINUSCOLON expression RBRACKET'
        p[0] = Partselect(p[1], p[3], Minus(
            p[3], p[5], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_pointer(self, p):
        'pointer : identifier LBRACKET expression RBRACKET'
        p[0] = Pointer(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_pointer_pointer(self, p):
        'pointer : pointer LBRACKET expression RBRACKET'
        p[0] = Pointer(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_const_expression_intnum(self, p):
        'const_expression : intnumber'
        p[0] = IntConst(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_const_expression_floatnum(self, p):
        'const_expression : floatnumber'
        p[0] = FloatConst(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_const_expression_stringliteral(self, p):
        'const_expression : stringliteral'
        p[0] = StringConst(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_floatnumber(self, p):
        'floatnumber : FLOATNUMBER'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_intnumber(self, p):
        """intnumber : INTNUMBER_DEC
        | SIGNED_INTNUMBER_DEC
        | INTNUMBER_BIN
        | SIGNED_INTNUMBER_BIN
        | INTNUMBER_OCT
        | SIGNED_INTNUMBER_OCT
        | INTNUMBER_HEX
        | SIGNED_INTNUMBER_HEX
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # String Literal
    def p_stringliteral(self, p):
        'stringliteral : STRING_LITERAL'
        p[0] = p[1][1:-1]  # strip \" and \"
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    # Always
    def p_always(self, p):
        'always : ALWAYS senslist always_statement'
        p[0] = Always(p[2], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p[3].end_lineno

    def p_always_ff(self, p):
        'always_ff : ALWAYS_FF senslist always_statement'
        p[0] = AlwaysFF(p[2], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p[3].end_lineno

    def p_always_comb(self, p):
        'always_comb : ALWAYS_COMB senslist always_statement'
        p[0] = AlwaysComb(p[2], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p[3].end_lineno

    def p_always_latch(self, p):
        'always_latch : ALWAYS_LATCH senslist always_statement'
        p[0] = AlwaysLatch(p[2], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p[3].end_lineno

    def p_sens_egde_paren(self, p):
        'senslist : AT LPAREN edgesigs RPAREN'
        p[0] = SensList(p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_posedgesig(self, p):
        'edgesig : POSEDGE edgesig_base'
        p[0] = Sens(p[2], 'posedge', lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_negedgesig(self, p):
        'edgesig : NEGEDGE edgesig_base'
        p[0] = Sens(p[2], 'negedge', lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_edgesig_base_identifier(self, p):
        'edgesig_base : identifier'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_edgesig_base_pointer(self, p):
        'edgesig_base : pointer'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_edgesigs(self, p):
        'edgesigs : edgesigs SENS_OR edgesig'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_edgesigs_comma(self, p):
        'edgesigs : edgesigs COMMA edgesig'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_edgesigs_one(self, p):
        'edgesigs : edgesig'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_sens_empty(self, p):
        'senslist : empty'
        p[0] = SensList(
            (Sens(None, 'all', lineno=p.lineno(1)),), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_sens_level(self, p):
        'senslist : AT levelsig'
        p[0] = SensList((p[2],), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_sens_level_paren(self, p):
        'senslist : AT LPAREN levelsigs RPAREN'
        p[0] = SensList(p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_levelsig(self, p):
        'levelsig : levelsig_base'
        p[0] = Sens(p[1], 'level', lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_levelsig_base_identifier(self, p):
        'levelsig_base : identifier'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_levelsig_base_pointer(self, p):
        'levelsig_base : pointer'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_levelsig_base_partselect(self, p):
        'levelsig_base : partselect'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_levelsigs(self, p):
        'levelsigs : levelsigs SENS_OR levelsig'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_levelsigs_comma(self, p):
        'levelsigs : levelsigs COMMA levelsig'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_levelsigs_one(self, p):
        'levelsigs : levelsig'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_sens_all(self, p):
        'senslist : AT TIMES'
        p[0] = SensList(
            (Sens(None, 'all', lineno=p.lineno(1)),), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_sens_all_paren(self, p):
        'senslist : AT LPAREN TIMES RPAREN'
        p[0] = SensList(
            (Sens(None, 'all', lineno=p.lineno(1)),), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_basic_statement(self, p):
        """basic_statement : if_statement
        | case_statement
        | casex_statement
        | casez_statement
        | unique_case_statement
        | for_statement
        | while_statement
        | event_statement
        | wait_statement
        | forever_statement
        | block
        | namedblock
        | parallelblock
        | blocking_substitution
        | nonblocking_substitution
        | single_statement
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_always_statement(self, p):
        'always_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_blocking_substitution(self, p):
        'blocking_substitution : delays lvalue EQUALS delays rvalue SEMICOLON'
        p[0] = BlockingSubstitution(p[2], p[5], p[1], p[4], lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(2))
        p[0].end_lineno = p.lineno(6)

    def p_blocking_substitution_base(self, p):
        'blocking_substitution_base : delays lvalue EQUALS delays rvalue'
        p[0] = BlockingSubstitution(p[2], p[5], p[1], p[4], lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(2))

    def p_nonblocking_substitution(self, p):
        'nonblocking_substitution : delays lvalue LE delays rvalue SEMICOLON'
        p[0] = NonblockingSubstitution(
            p[2], p[5], p[1], p[4], lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(2))
        p[0].end_lineno = p.lineno(6)

    # --------------------------------------------------------------------------
    def p_delays(self, p):
        'delays : DELAY LPAREN expression RPAREN'
        p[0] = DelayStatement(p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_delays_identifier(self, p):
        'delays : DELAY identifier'
        p[0] = DelayStatement(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_delays_intnumber(self, p):
        'delays : DELAY intnumber'
        p[0] = DelayStatement(
            IntConst(p[2], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_delays_floatnumber(self, p):
        'delays : DELAY floatnumber'
        p[0] = DelayStatement(FloatConst(
            p[2], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_delays_empty(self, p):
        'delays : empty'
        p[0] = None

    # --------------------------------------------------------------------------
    def p_block(self, p):
        'block : BEGIN block_statements END'
        p[0] = Block(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(3)

    def p_block_empty(self, p):
        'block : BEGIN END'
        p[0] = Block((), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(2)

    def p_block_statements(self, p):
        'block_statements : block_statements block_statement'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_block_statements_one(self, p):
        'block_statements : block_statement'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_block_statement(self, p):
        'block_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_namedblock(self, p):
        'namedblock : BEGIN COLON ID namedblock_statements END'
        p[0] = Block(p[4], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(5)

    def p_namedblock_empty(self, p):
        'namedblock : BEGIN COLON ID END'
        p[0] = Block((), p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(4)

    def p_namedblock_statements(self, p):
        'namedblock_statements : namedblock_statements namedblock_statement'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_namedblock_statements_one(self, p):
        'namedblock_statements : namedblock_statement'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_namedblock_statement(self, p):
        """namedblock_statement : basic_statement
        | decl
        | integerdecl
        | realdecl
        | parameterdecl
        | localparamdecl
        """
        if isinstance(p[1], Decl):
            for r in p[1].list:
                if (not isinstance(r, Reg) and not isinstance(r, Wire) and
                    not isinstance(r, Integer) and not isinstance(r, Real) and
                        not isinstance(r, Parameter) and not isinstance(r, Localparam)):
                    raise ParseError("Syntax Error")
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_parallelblock(self, p):
        'parallelblock : FORK block_statements JOIN'
        p[0] = ParallelBlock(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_parallelblock_empty(self, p):
        'parallelblock : FORK JOIN'
        p[0] = ParallelBlock((), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_if_statement(self, p):
        'if_statement : IF LPAREN cond RPAREN true_statement ELSE else_statement'
        p[0] = IfStatement(p[3], p[5], p[7], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p[7].end_lineno

    def p_if_statement_woelse(self, p):
        'if_statement : IF LPAREN cond RPAREN true_statement'
        p[0] = IfStatement(p[3], p[5], None, lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p[5].end_lineno

    def p_if_statement_delay(self, p):
        'if_statement : delays IF LPAREN cond RPAREN true_statement ELSE else_statement'
        p[0] = IfStatement(p[4], p[6], p[8], lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(2))
        p[0].end_lineno = p[8].end_lineno

    def p_if_statement_woelse_delay(self, p):
        'if_statement : delays IF LPAREN cond RPAREN true_statement'
        p[0] = IfStatement(p[4], p[6], None, lineno=p.lineno(2))
        p.set_lineno(0, p.lineno(2))
        p[0].end_lineno = p[6].end_lineno

    def p_cond(self, p):
        'cond : expression'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_ifcontent_statement(self, p):
        'ifcontent_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_true_statement(self, p):
        'true_statement : ifcontent_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_else_statement(self, p):
        'else_statement : ifcontent_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_for_statement(self, p):
        'for_statement : FOR LPAREN forpre forcond forpost RPAREN forcontent_statement'
        p[0] = ForStatement(p[3], p[4], p[5], p[7], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_forpre(self, p):
        'forpre : blocking_substitution'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_forpre_empty(self, p):
        'forpre : SEMICOLON'
        p[0] = None
        p.set_lineno(0, p.lineno(1))

    def p_forcond(self, p):
        'forcond : cond SEMICOLON'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_forcond_empty(self, p):
        'forcond : SEMICOLON'
        p[0] = None
        p.set_lineno(0, p.lineno(1))

    def p_forpost(self, p):
        'forpost : blocking_substitution_base'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_forpost_empty(self, p):
        'forpost : empty'
        p[0] = None

    def p_forcontent_statement(self, p):
        'forcontent_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_while_statement(self, p):
        'while_statement : WHILE LPAREN cond RPAREN whilecontent_statement'
        p[0] = WhileStatement(p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_whilecontent_statement(self, p):
        'whilecontent_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_case_statement(self, p):
        'case_statement : CASE LPAREN case_comp RPAREN casecontent_statements ENDCASE'
        p[0] = CaseStatement(p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(6)

    def p_casex_statement(self, p):
        'casex_statement : CASEX LPAREN case_comp RPAREN casecontent_statements ENDCASE'
        p[0] = CasexStatement(p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(6)

    def p_casez_statement(self, p):
        'casez_statement : CASEZ LPAREN case_comp RPAREN casecontent_statements ENDCASE'
        p[0] = CasezStatement(p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(6)

    def p_unique_case_statement(self, p):
        'unique_case_statement : UNIQUE CASE LPAREN case_comp RPAREN casecontent_statements ENDCASE'
        p[0] = UniqueCaseStatement(p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(7)

    def p_case_comp(self, p):
        'case_comp : expression'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_casecontent_statements(self, p):
        'casecontent_statements : casecontent_statements casecontent_statement'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_casecontent_statements_one(self, p):
        'casecontent_statements : casecontent_statement'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_casecontent_statement(self, p):
        'casecontent_statement : casecontent_condition COLON basic_statement'
        p[0] = Case(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_casecontent_condition_single(self, p):
        'casecontent_condition : casecontent_condition COMMA expression'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_casecontent_condition_one(self, p):
        'casecontent_condition : expression'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_casecontent_statement_default(self, p):
        'casecontent_statement : DEFAULT COLON basic_statement'
        p[0] = Case(None, p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_initial(self, p):
        'initial : INITIAL initial_statement'
        p[0] = Initial(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_initial_statement(self, p):
        'initial_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_event_statement(self, p):
        'event_statement : senslist SEMICOLON'
        p[0] = EventStatement(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_wait_statement(self, p):
        'wait_statement : WAIT LPAREN cond RPAREN waitcontent_statement'
        p[0] = WaitStatement(p[3], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_waitcontent_statement(self, p):
        'waitcontent_statement : basic_statement'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_waitcontent_statement_empty(self, p):
        'waitcontent_statement : SEMICOLON'
        p[0] = None
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_forever_statement(self, p):
        'forever_statement : FOREVER basic_statement'
        p[0] = ForeverStatement(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_instance(self, p):
        'instance : ID parameterlist instance_bodylist SEMICOLON'
        instancelist = []
        for instance_name, instance_ports, instance_array in p[3]:
            instancelist.append(Instance(p[1], instance_name, instance_ports,
                                         p[2], instance_array, lineno=p.lineno(1)))
        p[0] = InstanceList(p[1], p[2], tuple(
            instancelist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(4)

    def p_instance_or(self, p):
        'instance : SENS_OR parameterlist instance_bodylist SEMICOLON'
        instancelist = []
        for instance_name, instance_ports, instance_array in p[3]:
            instancelist.append(Instance(p[1], instance_name, instance_ports,
                                         p[2], instance_array, lineno=p.lineno(1)))
        p[0] = InstanceList(p[1], p[2], tuple(
            instancelist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(4)

    def p_instance_bodylist(self, p):
        'instance_bodylist : instance_bodylist COMMA instance_body'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_bodylist_one(self, p):
        'instance_bodylist : instance_body'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_body(self, p):
        'instance_body : ID LPAREN instance_ports RPAREN'
        p[0] = (p[1], p[3], None)
        p.set_lineno(0, p.lineno(1))

    def p_instance_body_array(self, p):
        'instance_body : ID width LPAREN instance_ports RPAREN'
        p[0] = (p[1], p[4], p[2])
        p.set_lineno(0, p.lineno(1))

    def p_instance_noname(self, p):
        'instance : ID instance_bodylist_noname SEMICOLON'
        instancelist = []
        for instance_name, instance_ports, instance_array in p[2]:
            instancelist.append(Instance(p[1], instance_name, instance_ports,
                                         (), instance_array, lineno=p.lineno(1)))
        p[0] = InstanceList(p[1], (), tuple(instancelist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(3)

    def p_instance_or_noname(self, p):
        'instance : SENS_OR instance_bodylist_noname SEMICOLON'
        instancelist = []
        for instance_name, instance_ports, instance_array in p[2]:
            instancelist.append(Instance(p[1], instance_name, instance_ports,
                                         (), instance_array, lineno=p.lineno(1)))
        p[0] = InstanceList(p[1], (), tuple(instancelist), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(3)

    def p_instance_bodylist_noname(self, p):
        'instance_bodylist_noname : instance_bodylist_noname COMMA instance_body_noname'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_bodylist_one_noname(self, p):
        'instance_bodylist_noname : instance_body_noname'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_body_noname(self, p):
        'instance_body_noname : LPAREN instance_ports RPAREN'
        p[0] = ('', p[2], None)
        p.set_lineno(0, p.lineno(1))

    def p_parameterlist(self, p):
        'parameterlist : DELAY LPAREN param_args RPAREN'
        p[0] = p[3]
        p.set_lineno(0, p.lineno(1))

    def p_parameterlist_noname(self, p):
        'parameterlist : DELAY LPAREN param_args_noname RPAREN'
        p[0] = p[3]
        p.set_lineno(0, p.lineno(1))

    def p_parameterlist_empty(self, p):
        'parameterlist : empty'
        p[0] = ()

    def p_param_args_noname(self, p):
        'param_args_noname : param_args_noname COMMA param_arg_noname'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_param_args_noname_one(self, p):
        'param_args_noname : param_arg_noname'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_param_args(self, p):
        'param_args : param_args COMMA param_arg'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_param_args_one(self, p):
        'param_args : param_arg'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_param_args_empty(self, p):
        'param_args : empty'
        p[0] = ()

    def p_param_arg_noname_exp(self, p):
        'param_arg_noname : expression'
        p[0] = ParamArg(None, p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_param_arg_exp(self, p):
        'param_arg : DOT ID LPAREN expression RPAREN'
        p[0] = ParamArg(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_instance_ports(self, p):
        """instance_ports : instance_ports_list
        | instance_ports_arg
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_instance_ports_list(self, p):
        'instance_ports_list : instance_ports_list COMMA instance_port_list'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_ports_list_one(self, p):
        'instance_ports_list : instance_port_list'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_ports_list_empty(self, p):
        'instance_ports_list : empty'
        p[0] = ()
        p.set_lineno(0, p.lineno(1))

    def p_instance_port_list(self, p):
        'instance_port_list : expression'
        p[0] = PortArg(None, p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_instance_ports_arg(self, p):
        'instance_ports_arg : instance_ports_arg COMMA instance_port_arg'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_ports_arg_one(self, p):
        'instance_ports_arg : instance_port_arg'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_instance_port_arg(self, p):
        'instance_port_arg : DOT ID LPAREN identifier RPAREN'
        p[0] = PortArg(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_instance_port_arg_exp(self, p):
        'instance_port_arg : DOT ID LPAREN expression RPAREN'
        p[0] = PortArg(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_instance_port_arg_none(self, p):
        'instance_port_arg : DOT ID LPAREN RPAREN'
        p[0] = PortArg(p[2], None, lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_genvardecl(self, p):
        'genvardecl : GENVAR genvarlist SEMICOLON'
        p[0] = Decl(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_genvarlist(self, p):
        'genvarlist : genvarlist COMMA genvar'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_genvarlist_one(self, p):
        'genvarlist : genvar'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_genvar(self, p):
        'genvar : ID'
        p[0] = Genvar(name=p[1],
                      width=Width(msb=IntConst('31', lineno=p.lineno(1)),
                                  lsb=IntConst('0', lineno=p.lineno(1)),
                                  lineno=p.lineno(1)),
                      lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_generate(self, p):
        'generate : GENERATE generate_items ENDGENERATE'
        p[0] = GenerateStatement(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(3)

    def p_generate_items_empty(self, p):
        'generate_items : empty'
        p[0] = ()
        p.set_lineno(0, p.lineno(1))

    def p_generate_items(self, p):
        'generate_items : generate_items generate_item'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_generate_items_one(self, p):
        'generate_items : generate_item'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_generate_item(self, p):
        """generate_item : standard_item
        | generate_if
        | generate_for
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_generate_block(self, p):
        'generate_block : BEGIN generate_items END'
        p[0] = Block(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(3)

    def p_generate_named_block(self, p):
        'generate_block : BEGIN COLON ID generate_items END'
        p[0] = Block(p[4], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(5)

    def p_generate_if(self, p):
        'generate_if : IF LPAREN cond RPAREN gif_true_item ELSE gif_false_item'
        p[0] = IfStatement(p[3], p[5], p[7], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_generate_if_woelse(self, p):
        'generate_if : IF LPAREN cond RPAREN gif_true_item'
        p[0] = IfStatement(p[3], p[5], None, lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_generate_if_true_item(self, p):
        """gif_true_item : generate_item
        | generate_block
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_generate_if_false_item(self, p):
        """gif_false_item : generate_item
        | generate_block
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_generate_for(self, p):
        'generate_for : FOR LPAREN forpre forcond forpost RPAREN generate_forcontent'
        p[0] = ForStatement(p[3], p[4], p[5], p[7], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_generate_forcontent(self, p):
        """generate_forcontent : generate_item
        | generate_block
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_systemcall_noargs(self, p):
        'systemcall : DOLLER ID'
        p[0] = SystemCall(p[2], (), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_systemcall(self, p):
        'systemcall : DOLLER ID LPAREN sysargs RPAREN'
        p[0] = SystemCall(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_systemcall_signed(self, p):  # for $signed system task
        'systemcall : DOLLER SIGNED LPAREN sysargs RPAREN'
        p[0] = SystemCall(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_sysargs(self, p):
        'sysargs : sysargs COMMA sysarg'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_sysargs_one(self, p):
        'sysargs : sysarg'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_sysargs_empty(self, p):
        'sysargs : empty'
        p[0] = ()

    def p_sysarg(self, p):
        'sysarg : expression'
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_function(self, p):
        'function : FUNCTION width ID SEMICOLON function_statement ENDFUNCTION'
        p[0] = Function(p[3], p[2], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(6)

    def p_function_nowidth(self, p):
        'function : FUNCTION ID SEMICOLON function_statement ENDFUNCTION'
        p[0] = Function(p[2],
                        Width(IntConst('0', lineno=p.lineno(1)),
                              IntConst('0', lineno=p.lineno(1)),
                              lineno=p.lineno(1)),
                        p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(5)

    def p_function_integer(self, p):
        'function : FUNCTION INTEGER ID SEMICOLON function_statement ENDFUNCTION'
        p[0] = Function(p[3],
                        Width(IntConst('31', lineno=p.lineno(1)),
                              IntConst('0', lineno=p.lineno(1)),
                              lineno=p.lineno(1)),
                        p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(6)

    def p_function_statement(self, p):
        'function_statement : funcvardecls function_calc'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_funcvardecls(self, p):
        'funcvardecls : funcvardecls funcvardecl'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_funcvardecls_one(self, p):
        'funcvardecls : funcvardecl'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_funcvardecl(self, p):
        """funcvardecl : decl
        | integerdecl
        """
        if isinstance(p[1], Decl):
            for r in p[1].list:
                if (not isinstance(r, Input) and not isinstance(r, Reg) and
                        not isinstance(r, Integer)):
                    raise ParseError("Syntax Error")
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_function_calc(self, p):
        """function_calc : blocking_substitution
        | if_statement
        | for_statement
        | while_statement
        | case_statement
        | casex_statement
        | casez_statement
        | block
        | namedblock
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_functioncall(self, p):
        'functioncall : identifier LPAREN func_args RPAREN'
        p[0] = FunctionCall(p[1], p[3], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_func_args(self, p):
        'func_args : func_args COMMA expression'
        p[0] = p[1] + (p[3],)
        p.set_lineno(0, p.lineno(1))

    def p_func_args_one(self, p):
        'func_args : expression'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_func_args_empty(self, p):
        'func_args : empty'
        p[0] = ()

    # --------------------------------------------------------------------------
    def p_task(self, p):
        'task : TASK ID SEMICOLON task_statement ENDTASK'
        p[0] = Task(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_task_statement(self, p):
        'task_statement : taskvardecls task_calc'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_taskvardecls(self, p):
        'taskvardecls : taskvardecls taskvardecl'
        p[0] = p[1] + (p[2],)
        p.set_lineno(0, p.lineno(1))

    def p_taskvardecls_one(self, p):
        'taskvardecls : taskvardecl'
        p[0] = (p[1],)
        p.set_lineno(0, p.lineno(1))

    def p_taskvardecls_empty(self, p):
        'taskvardecls : empty'
        p[0] = ()

    def p_taskvardecl(self, p):
        """taskvardecl : decl
        | integerdecl
        """
        if isinstance(p[1], Decl):
            for r in p[1].list:
                if (not isinstance(r, Input) and not isinstance(r, Reg) and
                        not isinstance(r, Integer)):
                    raise ParseError("Syntax Error")
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    def p_task_calc(self, p):
        """task_calc : blocking_substitution
        | if_statement
        | for_statement
        | while_statement
        | case_statement
        | casex_statement
        | casez_statement
        | block
        | namedblock
        """
        p[0] = p[1]
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_identifier(self, p):
        'identifier : ID'
        p[0] = Identifier(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_scope_identifier(self, p):
        'identifier : scope ID'
        p[0] = Identifier(p[2], p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_scope(self, p):
        'scope : identifier DOT'
        scope = () if p[1].scope is None else p[1].scope.labellist
        p[0] = IdentifierScope(
            scope + (IdentifierScopeLabel(p[1].name, lineno=p.lineno(1)),), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_scope_pointer(self, p):
        'scope : pointer DOT'
        scope = () if p[1].var.scope is None else p[1].var.scope.labellist
        p[0] = IdentifierScope(scope + (IdentifierScopeLabel(p[1].var.name,
                                                             p[1].ptr, lineno=p.lineno(1)),), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_disable(self, p):
        'disable : DISABLE ID'
        p[0] = Disable(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_single_statement_delays(self, p):
        'single_statement : DELAY expression SEMICOLON'
        p[0] = SingleStatement(DelayStatement(
            p[2], lineno=p.lineno(1)), lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(3)

    def p_single_statement_systemcall(self, p):
        'single_statement : systemcall SEMICOLON'
        p[0] = SingleStatement(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(2)

    def p_single_statement_disable(self, p):
        'single_statement : disable SEMICOLON'
        p[0] = SingleStatement(p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))
        p[0].end_lineno = p.lineno(2)

    # fix me: to support task-call-statement
    # def p_single_statement_taskcall(self, p):
    #    'single_statement : functioncall SEMICOLON'
    #    p[0] = SingleStatement(p[1], lineno=p.lineno(1))
    #    p.set_lineno(0, p.lineno(1))

    # def p_single_statement_taskcall_empty(self, p):
    #    'single_statement : taskcall SEMICOLON'
    #    p[0] = SingleStatement(p[1], lineno=p.lineno(1))
    #    p.set_lineno(0, p.lineno(1))

    # def p_taskcall_empty(self, p):
    #    'taskcall : identifier'
    #    p[0] = FunctionCall(p[1], (), lineno=p.lineno(1))
    #    p.set_lineno(0, p.lineno(1))

    # --------------------------------------------------------------------------
    def p_empty(self, p):
        'empty : '
        pass

    # --------------------------------------------------------------------------
    def p_error(self, p):
        self._raise_error(p)

    # --------------------------------------------------------------------------
    def _raise_error(self, p):
        if p:
            msg = 'before: "%s"' % p.value
            coord = self._coord(p.lineno)
        else:
            msg = 'at end of input'
            coord = None

        raise ParseError("%s: %s" % (coord, msg))

    def _coord(self, lineno, column=None):
        ret = [self.lexer.filename]
        ret.append('line:%s' % lineno)
        if column is not None:
            ret.append('column:%s' % column)
        return ' '.join(ret)


class ParseError(Exception):
    pass


class VerilogCodeParser(object):

    def __init__(self, filelist, preprocess_output='preprocess.output',
                 preprocess_include=None,
                 preprocess_define=None,
                 outputdir=".",
                 debug=True
                 ):
        self.preprocess_output = preprocess_output
        self.directives = ()
        self.preprocessor = VerilogPreprocessor(filelist, preprocess_output,
                                                preprocess_include,
                                                preprocess_define)
        self.parser = VerilogParser(outputdir=outputdir, debug=debug)

    def preprocess(self):
        self.preprocessor.preprocess()
        text = open(self.preprocess_output).read()
        os.remove(self.preprocess_output)
        return text

    def parse(self, preprocess_output='preprocess.output', debug=0):
        text = self.preprocess()
        ast = self.parser.parse(text, debug=debug)
        self.directives = self.parser.get_directives()
        return ast

    def get_directives(self):
        return self.directives


def parse(
    filelist,
    preprocess_include=None,
    preprocess_define=None,
    outputdir=".",
    debug=True
):
    codeparser = VerilogCodeParser(
        filelist,
        preprocess_include=preprocess_include,
        preprocess_define=preprocess_define,
        outputdir=outputdir,
        debug=debug
    )
    ast = codeparser.parse()
    directives = codeparser.get_directives()
    return ast, directives
