The VHDL IEEE 1076.1 Grammar

The original VHDL-87 parser by Peter Reintjes is based upon the syntax given in the appendix of VHDL: Hardware Description and Design , (Kluwer Academic Press, 1989) (Authors: Lipsett, Schaefer and Ussery). This parser has been upgraded to the IEEE 1076.1-1997 Standard of VHDL (to include VHDL-AMS constructs) by the first author as described here.

Most of the grammar rules are self explanatory, particularly since the DCG syntax is so close to the usual BNF syntax. For the most part, cuts (!) are for efficiency. When a rule contains a cut that affects the grammar in a fundamental way, it will usually be explained more fully.

3.1 Literals and Miscellaneous

The grammar rules first define such things as identifiers, constant values, and expressions involving monadic (e.g. NOT) and diadic (e.g. AND) operators. The values and expressions recognized here are used throughout the remaining grammar rules.


parse_error(Construct) :- 
                    write('PARSE-ERROR: Illegal '), 
                    write(Construct), write('.'), nl, fail.

Rule 1


vhdl_designator(ID) --> vhdl_identifier(ID), !.
vhdl_designator(op(ST)) --> vhdl_operator_symbol(ST).     

vhdl_operator_symbol(ST) --> [string(SL)], 
                             {name(ST,SL)}, 
                             {vhdl_operator(ST)}.

Rule 2


vhdl_literal(null) --> [null],!.
vhdl_literal(L)    --> [ bit_string(L) ], !.
vhdl_literal(L)    --> [ string(L) ], !.
vhdl_literal(L)    --> vhdl_abstract_literal(L).
vhdl_literal(L)    --> vhdl_enumeration_literal(L).
vhdl_literal(L)    --> vhdl_physical_literal(L).

Rule 3

We only have one kind of number at present which includes integers and floating point numbers.


vhdl_abstract_literal(F) --> [ number(F) ].

Rule 4


vhdl_enumeration_literal(char(L))  --> [ char(L) ], !.
vhdl_enumeration_literal(ID) --> vhdl_identifier(ID).

Rule 5


vhdl_physical_literal(pl(AL,ID)) -->
        vhdl_abstract_literal(AL), vhdl_mark(ID).

Rule 6

vhdl_identifier_list//1 is used where a comma-separated list of identifiers is required. vhdl_identifier_list_LA//1 is used where a list of identifiers is just one possible option. The significance of this will be clarified later.


vhdl_identifier(ID) --> [ID], { \+ vhdl_token(ID) }.

vhdl_identifier_list([ID|IDs]) -->
        vhdl_identifier(ID), !, 
        vhdl_identifier_list_aux(IDs).

vhdl_identifier_list([]) --> 
        { parse_error('identifier list')}.

vhdl_identifier_list_LA([ID|IDs]) -->
        vhdl_identifier(ID), !, 
        vhdl_identifier_list_aux(IDs).

vhdl_identifier_list_aux([ID|IDs]) -->
        [','], !, vhdl_identifier(ID),
        vhdl_identifier_list_aux(IDs).

vhdl_identifier_list_aux([]) --> [].

3.2 Design Unit

The Design Unit is the top-level construction of the parse tree, this is the data structure containing the information from an entire VHDL file.

Rule 7


vhdl_design_unit(design_unit(CI,Unit)) -->
        vhdl_opt_context_items(CI),
        vhdl_library_unit(Unit).

Rule 8


vhdl_library_unit(LU) --> vhdl_entity_declaration(LU).
vhdl_library_unit(LU) --> vhdl_configuration_declaration(LU).
vhdl_library_unit(LU) --> vhdl_package_declaration(LU).
vhdl_library_unit(LU) --> vhdl_architecture_body(LU).
vhdl_library_unit(LU) --> vhdl_package_body(LU).

Rule 9


vhdl_opt_context_items([CI|CIs]) -->
        vhdl_library_clause(CI),
        vhdl_get_more,   !,
        vhdl_opt_context_items(CIs).

vhdl_opt_context_items([CI|CIs]) -->
        vhdl_use_clause(CI),
        vhdl_get_more,   !,
        vhdl_opt_context_items(CIs).

vhdl_opt_context_items([]) --> [].

Whenever a structure inside a grammar rule ends with a semicolon, we must read in more tokens before we can continue. For this purpose we create two, zero-arity, DCG rules. The first, vhdl_get_more//0 will read in a new token line if the current token list is empty. This rule will fail if the current token line has not been exhausted.

The second rule, vhdl_opt_get_more//0 behaves similarly if it encounters an empty token list, but will simply return the current token list if it is not empty.


vhdl_get_more([], Next)   :- !, vhdl_get_token_line(Next).

vhdl_opt_get_more([],Next) :- !, vhdl_get_token_line(Next).
vhdl_opt_get_more(In,In).

Rule 10


vhdl_library_clause(library(IL)) -->
       [ library ], vhdl_identifier_list(IL).

Rule 11


vhdl_opt_use_clauses([UC|UCs]) -->
      vhdl_use_clause(UC), !, vhdl_opt_use_clauses(UCs).
vhdl_opt_use_clauses([ ]) --> [ ].

vhdl_use_clause(use([Name|Names])) -->
       [ use ], vhdl_selected_name(Name),
                vhdl_selected_names(Names).

vhdl_selected_names([Name|Names]) -->
       [ ',' ], !, vhdl_selected_name(Name),
                   vhdl_selected_names(Names).

vhdl_selected_names([]) --> [].

3.3 Library Units

Rule 12

The grammar for Rule 12 is incorrect as given in the appendix of VHDL: Hardware Design and Description. The discussion of the entity declaration on page 31 correctly (but informally) gives the correct form, but the grammar rule in the appendix leaves out the optional declarative items.

Compared with VHDL-87, VHDL-93 end statements are now more uniform in that they may optionally specify the construct type and the corresponding identifier or label.


vhdl_entity_declaration(entity(ID,GIL,PIL,DIs,Ss)) -->
       [ entity ],  vhdl_identifier(ID), [ is ],
         vhdl_opt_generic_statement(GIL),
         vhdl_opt_port_statement(PIL),
         vhdl_opt_declarative_items(entity,DIs),
         vhdl_opt_entity_body(Ss),
       [ end ], vhdl_opt_keyword(entity),
         vhdl_opt_identifier(ID).

vhdl_opt_entity_body(Ss) -->
         [ begin ], !, vhdl_entity_concurrent_statements(Ss).
vhdl_opt_entity_body([]) --> [].

vhdl_opt_generic_statement(IL) -->
        [ generic ], !, vhdl_interface_list(IL),
        vhdl_get_more.
          
vhdl_opt_generic_statement(null) --> [].

vhdl_opt_port_statement(IL) -->
        [ port ], !, vhdl_interface_list(IL),
        vhdl_get_more.
          
vhdl_opt_port_statement(null) --> [].

Rule 13


vhdl_architecture_body(arch(ID,Entity,DIs,Ss)) -->
       [ architecture ],  vhdl_identifier(ID),
            [ of ], vhdl_mark(Entity),
            [ is ], vhdl_opt_declarative_items(architecture,DIs),
       [ begin ],
         vhdl_concurrent_statements(Ss),
       [ end ], vhdl_opt_keyword(architecture), 
           vhdl_opt_identifier(ID).

Rule 14


vhdl_configuration_declaration(conf(ID,Entity,DIs,Block)) -->
       [ configuration ], vhdl_identifier(ID),
           [ of ], vhdl_mark(Entity), [ is ],
              vhdl_opt_declarative_items(configuration,DIs),
              vhdl_block_configuration(Block),
       [ end ], vhdl_opt_keyword(configuration),
         vhdl_opt_identifier(ID).

Rule 15


vhdl_package_declaration(package(ID,DIs)) -->
       [ package ], vhdl_identifier(ID), [ is ],
         vhdl_opt_declarative_items(package,DIs),
       [ end ], vhdl_opt_keyword(package),
         vhdl_opt_identifier(ID).

Rule 16


vhdl_package_body(package_body(ID,DIs)) -->
       [ package,  body ], vhdl_identifier(ID), [ is ],
         vhdl_opt_declarative_items(package_body,DIs),
       [ end ], vhdl_opt_keywords(package, body),
         vhdl_opt_identifier(ID).

vhdl_opt_identifier(ID)  --> vhdl_identifier(ID), !.
vhdl_opt_identifier(_)--> [].

vhdl_opt_keyword(KID)  --> [ KID ], !.
vhdl_opt_keyword(_)--> [].

vhdl_opt_keywords(KID1,KID2)  --> [ KID1, KID2 ], !.
vhdl_opt_keywords(_,_)--> [].

The last part of this production, vhdl_opt_identifier//1 (resp. vhdl_opt_keyword//1//2 ), is called with its argument instantiated. This will succeed not only when the identifier (resp. keyword) found in the input stream matches the one recognized at the beginning of the rule, but will also succeed if there is no identifier (resp. keyword). This is in contrast to the other optional rules which instantiate their arguments to null.

3.4 Declarative Items

The original VHDL-87 parser incorrectly permitted all possible declarative items for all construct types (that can contain declarations). Here we allow only those declarative items that are explicitly permitted by VHDL for each construct type.

The first clause is applicable only to configuration . The rest of the clauses take care of all the other construct types.

Rule 17


vhdl_declarative_item(configuration,DI) --> 
                   !, (  vhdl_attribute_specification(DI)
                      ;  vhdl_use_clause(DI)
                      ;  vhdl_group_declaration(DI)
                      ).

vhdl_declarative_item(_,DI) -->
                    (  vhdl_type_declaration(DI)
                    ;  vhdl_subtype_declaration(DI)
                    ;  vhdl_constant_declaration(DI)
                    ;  vhdl_ordinary_variable_declaration(DI)
                    ;  vhdl_file_declaration(DI)
                    ;  vhdl_alias_declaration(DI)
                    ;  vhdl_use_clause(DI)
                    ;  vhdl_group_template_declaration(DI)
                    ;  vhdl_group_declaration(DI)
                    ).


vhdl_declarative_item(C,DI) --> 
                   { nature_allowed(C) }, 
                      (  vhdl_nature_declaration(DI)
                       ; vhdl_subnature_declaration(DI)
                       ; vhdl_terminal_declaration(DI)
                       ; ( { C \== package }, 
                           vhdl_quantity_declaration(DI) )
                   ).

vhdl_declarative_item(C,DI) --> 
                     { shared_var_allowed(C) }, 
                     vhdl_shared_variable_declaration(DI).

vhdl_declarative_item(C,DI) --> 
                     { C == package } 
                          -> vhdl_subprogram_declaration(DI)
                          ;  vhdl_subprogram_declaration_or_body(DI).

vhdl_declarative_item(C,DI) --> 
                    ( { signal_allowed(C) }, 
                      (  vhdl_signal_declaration(DI)
                       ; vhdl_component_declaration(DI)
                       ; vhdl_configuration_specification(DI)
                       ; vhdl_disconnection_specification(DI)
                      )
                   ).

vhdl_declarative_item(C,DI) --> 
                     { C \== package_body },
                     (  vhdl_attribute_declaration(DI)
                      ; vhdl_attribute_specification(DI)
                     ).

vhdl_opt_declarative_items(Construct,[I|Is]) -->
        vhdl_declarative_item(Construct,I),
        vhdl_get_more,     !,
        vhdl_opt_declarative_items(Construct,Is).

vhdl_opt_declarative_items(_,[]) --> [].

signal_allowed(entity).             signal_allowed(architecture).
signal_allowed(package).            signal_allowed(block).

shared_var_allowed(entity).         shared_var_allowed(architecture).
shared_var_allowed(package).        shared_var_allowed(package_body).
shared_var_allowed(block).

nature_allowed(entity).               nature_allowed(architecture).
nature_allowed(package).              nature_allowed(block).

 

Rule 17.5

These following clauses are VHDL-AMS additions.

vhdl_procedural_declarative_item(DI) --> 
                    (  vhdl_subprogram_declaration(DI)
                    ;  vhdl_subprogram_body(DI)
                    ;  vhdl_type_declaration(DI)
                    ;  vhdl_subtype_declaration(DI)
                    ;  vhdl_constant_declaration(DI)
                    ;  vhdl_ordinary_variable_declaration(DI)
                    ;  vhdl_shared_variable_declaration(DI)
                    ;  vhdl_alias_declaration(DI)
                    ;  vhdl_attribute_declaration(DI)
                    ;  vhdl_attribute_specification(DI)
                    ;  vhdl_use_clause(DI)
                    ;  vhdl_group_template_declaration(DI)
                    ;  vhdl_group_declaration(DI)
                    ).
vhdl_procedural_declarative_part([DI | DL]) --> 
                    vhdl_procedural_declarative_item(DI), 
                    vhdl_get_more, !, 
                    vhdl_procedural_declarative_part(DL).
vhdl_procedural_declarative_part([]) --> [].

vhdl_procedural_statement_part([DI | DL]) --> 
                    vhdl_sequential_statement(DI), 
                    vhdl_get_more, !, 
                    vhdl_procedural_statement_part(DL).
vhdl_procedural_statement_part([]) --> [].

3.5 Groups

VHDL-93 supports the concept of groups and group templates not present in VHDL-87.

Rule 17a


vhdl_group_template_declaration(group_template(TID,CL)) --> 
              [ group ], vhdl_identifier(TID), [ is ],
              [ '(' ], vhdl_entity_class_entry_list(CL), [ ')' ].

vhdl_entity_class_entry_list([C|CL]) -->
              vhdl_entity_class_entry(C), !,
              vhdl_entity_class_entry_list_aux(CL).

vhdl_entity_class_entry_list([]) -->
              { parse_error('group entity class list') }.

vhdl_entity_class_entry_list_aux([C|CL]) -->
              [ ',' ], !, vhdl_entity_class_entry(C),
              vhdl_entity_class_entry_list_aux(CL).

vhdl_entity_class_entry_list_aux([]) --> [ ].

vhdl_entity_class_entry(entity_class(EC,One_Any)) --> 
             vhdl_entity_class(EC),
             (  [ '<>' ], !, { One_Any = any }
             ;  { One_Any = null } ).

Rule 17b


vhdl_group_declaration(group(ID,TID,CL)) --> 
             [ group ],  vhdl_identifier(ID), [ ':' ],
             vhdl_name(TID), 
             [ '(' ], vhdl_group_constituents(CL), [ ')' ].

vhdl_group_constituents([L|CL]) --> 
             vhdl_constituent(L),
             vhdl_group_constituents_aux(CL).

vhdl_group_constituents([]) --> 
             { parse_error('group constituents') }.

vhdl_group_constituents_aux([L|CL]) --> 
             [ ',' ], !, vhdl_constituent(L),  
             vhdl_group_constituents_aux(CL).

vhdl_group_constituents_aux([]) -->  [ ].

vhdl_constituent(L)       --> vhdl_name(L).

vhdl_constituent(char(L)) --> [ char(L) ].

% CAUTION: Cut at the end of vhdl_name destructively 
% interferes with backtracking for selected/indexed names
% because identifier is a prefix of the latter.
 

3.6 Subprograms

Here we give rules for subprogram declaration, and for both subprogram declaration and body combined. If we read a subprogram specification and the next token is not the keyword is, then we have just read a subprogram declaration. It would be impossible to backtrack out of the subprogram declaration and try the subprogram body rule because several token lines may have been read while getting the interface-list part of the subprogram specification.

Rule 18


vhdl_subprogram_declaration(sub_program(SS,null)) -->
        vhdl_subprogram_specification(_,_,SS).

vhdl_subprogram_declaration_or_body(sub_program(SS,Body)) -->
        vhdl_subprogram_specification(Kind,Name,SS),
        vhdl_opt_subprogram_body(Kind,Name,Body).

Rule 19


vhdl_subprogram_specification(procedure,D,sub_spec(D,IL,null,null)) -->
        [ procedure ], vhdl_designator(D),
        vhdl_opt_interface_list(IL).
vhdl_subprogram_specification(function,D,sub_spec(D,IL,TM,P)) -->
        ( [ pure ],   !, { P = pure }
        ; [ impure ], !, { P = impure }
        ; [ ], { P = pure } ),
        [ function ],  vhdl_designator(D),
              vhdl_opt_interface_list(IL),
        [ return ], vhdl_mark(TM).

Rule 20


vhdl_opt_subprogram_body(Kind,Name,program_body(Is,Ss)) -->
        [ is ], !,
           vhdl_opt_declarative_items(subprogram,Is),
        [ begin ],
           vhdl_sequential_statements(Ss),
        [ end ], ([Kind], ! ; []), vhdl_opt_designator(Name).

vhdl_opt_subprogram_body(_,_,null) --> [].

vhdl_opt_designator(D) --> vhdl_designator(D),!.
vhdl_opt_designator(_) --> [].

Rule 20.5


vhdl_subprogram_body(sub_program(SS,program_body(Is,Sst))) -->
        vhdl_subprogram_specification(Kind,Name,SS),
        [ is ], !,
           vhdl_opt_declarative_items(subprogram,Is),
        [ begin ],
           vhdl_sequential_statements(Sst),
        [ end ], ([Kind], ! ; []), 
        vhdl_opt_designator(Name).

3.7 Interface Lists and Association Lists

Rule 21


vhdl_interface_list(Is) -->
        ['('], vhdl_interface_elements(Is).

vhdl_opt_interface_list(Is) --> vhdl_interface_list(Is),!.
vhdl_opt_interface_list([]) --> [].

vhdl_interface_elements([I|Is]) -->
        vhdl_interface_element(I),
        vhdl_ie_sub(Is).
 
vhdl_ie_sub([]) --> [')'].
vhdl_ie_sub(Is) -->
        vhdl_get_more, !,
        vhdl_interface_elements(Is).
In the above rule, semicolon is a separator, rather than a terminator.

Rule 22

The following rule has been modified to include VHDL-AMS.

vhdl_interface_element(interface_element(Class,IL,Mode,ST,Bus,Expr)) -->
        vhdl_opt_object_class(Class),
        vhdl_identifier_list_LA(IL), [':'],
        vhdl_opt_mode(Mode),
        ({Class == terminal} ->         
                              vhdl_subnature_indication(ST)
                           ;  vhdl_subtype_indication(ST)),
        vhdl_opt_bus(Bus), vhdl_opt_assignment(Expr),
        { constraint(Class,Mode,Bus,Expr) }.

constraint(constant,in,null,_).
constraint(constant,null,null,_).

constraint(variable,_,null,_).
constraint(shared_variable,_,null,_).

constraint(signal,_,_,_).

constraint(file,null,null,null).

constraint(quantity,in,null,_).
constraint(quantity,out,null,_).

constraint(terminal,null,null,null).

constraint(null,_,_,_).

Rule 23


vhdl_opt_mode(in)      --> [  in ], !.
vhdl_opt_mode(out)     --> [  out ], !.
vhdl_opt_mode(inout)   --> [ inout ], !.
vhdl_opt_mode(buffer)  --> [ buffer ], !.
vhdl_opt_mode(linkage) --> [ linkage ], !.
vhdl_opt_mode(null) --> [].

vhdl_opt_bus(bus) --> [ bus ], !.
vhdl_opt_bus(null) --> [].

Rule 24


vhdl_association_list([A|As]) -->
      ['('], vhdl_association_element(A),
             vhdl_more_association_list(As).

vhdl_more_association_list([])     --> [')'], !.
vhdl_more_association_list([A|As]) -->
        [','], vhdl_association_element(A),
        vhdl_more_association_list(As).

vhdl_opt_association_list(A)  --> vhdl_association_list(A).
vhdl_opt_association_list([]) --> [].

Rule 25


vhdl_association_element(element(Formal,Actual)) -->
      vhdl_opt_formal_part(Formal), vhdl_actual_part(Actual).

Rule 26


vhdl_formal_part(Name) --> vhdl_name(Name).

vhdl_opt_formal_part(Name) --> vhdl_formal_part(Name), ['=>'], !.
vhdl_opt_formal_part(null) --> [].

Rule 27


vhdl_actual_part(open) --> [ open ], !.
vhdl_actual_part(Expr) --> vhdl_expression(Expr).

3.8 Names and Expressions

This section contains several departures from the grammar described in the VHDL book and the original parser implementation because there are errors in them. For instance, they do not deal with unary operators and non-associative operators correctly. The grammar does not permit expressions such as ( - abs 4 * 2 + 8 ) , but permits expressions such as ( x nor y nor z ) and ( x + -y ) and ( x < y < z ) . The code given here follows the VHDL grammar closely.

Rule 28


vhdl_mark(_,[],_) :- !, fail.
 

vhdl_mark(attr_name([N,A|As])) -->
                 [N, attr(A)], !, vhdl_opt_attrs(As).
vhdl_mark(ID) --> vhdl_identifier(ID).
vhdl_mark(SN) --> vhdl_selected_name(SN).

vhdl_opt_mark(M)    --> vhdl_mark(M).
vhdl_opt_mark(null) --> [].

vhdl_expression(_,[],_) :- !, fail.
 

Rule 29

The rules for VHDL expressions are only complicated by the handling of operators.


vhdl_expression(E) --> 
         vhdl_relation(F), vhdl_opt_expression(F,E).

vhdl_opt_expression(F, expr(Op,[F,E|EL])) -->
         vhdl_boolop_associative(Op), !, 
         vhdl_relation(E), 
         vhdl_relation_list(Op,EL).

vhdl_opt_expression(F, expr(Op,F,E)) -->
         vhdl_boolop_non_associative(Op), !, 
         vhdl_relation(E).

vhdl_opt_expression(E,E) --> [ ].

vhdl_relation_list(Op,[E|EL]) -->
         vhdl_boolop_associative(Op), !, 
         vhdl_relation(E), 
	 vhdl_relation_list(Op,EL).

vhdl_relation_list(_,[ ]) --> [ ].

vhdl_relation(E) -->
         vhdl_shift_expression(F),
         vhdl_opt_relation(F,E).

vhdl_opt_relation(F,rel(Op,F,E)) --> 
         vhdl_relational_operator(Op), !, 
         vhdl_shift_expression(E).

vhdl_opt_relation(E,E) --> [ ].

vhdl_shift_expression(E) -->
         vhdl_simple_expression(F),
         vhdl_opt_shift_expression(F,E).

vhdl_opt_shift_expression(F,shift(Op,F,E)) --> 
         vhdl_shift_operator(Op), !, 
         vhdl_simple_expression(E).

vhdl_opt_shift_expression(E,E) --> [ ].

vhdl_simple_expression(E) -->
         vhdl_sign(Uop),  !,  vhdl_term(F),
         vhdl_opt_simple_expression(signed(Uop,F),E).

vhdl_simple_expression(E) -->
         vhdl_term(F), vhdl_opt_simple_expression(F,E).

vhdl_opt_simple_expression(F,E) --> 
         vhdl_adding_operator(Op), !, 
         vhdl_term(T),
         vhdl_opt_simple_expression(term(F,Op,T),E).

vhdl_opt_simple_expression(E,E) --> [ ].

vhdl_term(E) -->
         vhdl_factor(F), vhdl_opt_term(F,E).

vhdl_opt_term(F,E) --> 
         vhdl_multiplying_operator(Op), !, 
         vhdl_factor(T),
         vhdl_opt_term(factor(F,Op,T),E).

vhdl_opt_term(E,E) --> [ ].

vhdl_factor(nott(P)) -->
         [ not ], !, vhdl_primary(P).

vhdl_factor(abs(P)) -->
         [ abs ], !, vhdl_primary(P).

vhdl_factor(F) -->
         vhdl_primary(P1),
         ( [ '**' ], !,  vhdl_primary(P2), 
           { F = expt(P1, P2) }
         ; { F = P1 } ).

Rule 30


vhdl_primary(P) --> ['('], vhdl_expression(P), [')'].
vhdl_primary(P) --> vhdl_aggregate(P).
vhdl_primary(P) --> vhdl_function_call(P).
vhdl_primary(P) --> vhdl_qualified_expression(P).
vhdl_primary(P) --> vhdl_name(P).
vhdl_primary(P) --> vhdl_literal(P).
vhdl_primary(P) --> vhdl_type_conversion(P).
vhdl_primary(P) --> vhdl_allocator(P).

Rule 31


vhdl_name(_) --> [N], { vhdl_keyword(N),!,fail }.
vhdl_name(attr_name([N,A|As])) -->
                 vhdl_designator(N), [attr(A)], vhdl_opt_attrs(As).
% No "!" because it can match a valid prefix of "vhdl_attribute_name(N)." 
vhdl_name(N) --> vhdl_designator(N).
vhdl_name(N) --> vhdl_selected_name(N).
vhdl_name(N) --> vhdl_indexed_name(N).
vhdl_name(N) --> vhdl_slice_name(N).
vhdl_name(N) --> vhdl_attribute_name(N).

vhdl_opt_attrs([A|As]) --> [attr(A)], vhdl_opt_attrs(As).
vhdl_opt_attrs([])     --> [].

Rule 32


vhdl_selected_name(vhdl_name(P,S)) -->
       vhdl_prefix(P), ['.'], vhdl_suffix(S).

vhdl_prefix(_,  [],_) :- !,fail.
 

Rule 33

The prefix definition given in VHDL: Hardware Description and Design is problematic in that it is defined in terms of names which are in turn defined as selected_names or indexed_names each of which can begin with a prefix. Thus, the rules for vhdl_prefix//1, as given by the book would be:


vhdl_prefix(P) --> vhdl_name(P).
vhdl_prefix(P) --> vhdl_function_call(P).

This, through vhdl_name//1 and vhdl_selected_name//1 results in a left-recursive definition unsuitable for implementation in Prolog. So we have define vhdl_prefix//1 to be any number of primitive prefixes composed of an identifier and the punctuation of a selected or indexed name, followed by a prefix. This right-recursive production will recognize the same compound prefixes as specified by the book.


vhdl_prefix(prefix(Prefix)) -->
        vhdl_designator(P1), vhdl_prefix(P1,Prefix).

vhdl_prefix(P1,function_call(P1,Args,P2)) -->
        vhdl_association_list(Args), vhdl_prefix2(P2).

vhdl_prefix(P1,slice(P1,R,P2)) -->
        [ '(' ], vhdl_discrete_range(R), [')'], vhdl_prefix2(P2).

vhdl_prefix(P1,select(P1,P2)) -->
        [ '.' ], vhdl_prefix2(P2).

vhdl_prefix(P1,attribute(P1,Attr,E,P2)) -->
        [ attr(Attr) ], vhdl_opt_paren_expression(E), vhdl_prefix2(P2).

vhdl_prefix(P1,P1) --> []. % Just the designator

vhdl_prefix2(P) --> vhdl_prefix(P).
vhdl_prefix2(null) --> [].

vhdl_opt_paren_expression(E) -->
         [ '(' ], vhdl_expression(E), [ ')' ], !.
vhdl_opt_paren_expression(null) --> [].

Rule 34


vhdl_suffix(all)       --> [ all ].
vhdl_suffix(char(C))   --> [ char(C) ].
vhdl_suffix(dot(S,S2)) --> vhdl_designator(S), ['.'], !, vhdl_suffix(S2).
vhdl_suffix(S)         --> vhdl_designator(S).

Rule 35


vhdl_indexed_name(vhdl_name(P,[E|Es])) -->
       vhdl_prefix(P), ['('],
       vhdl_expression(E),
       vhdl_expression_list(Es).

vhdl_expression_list([]) --> [')'], !.

vhdl_expression_list([Expr|Exprs]) -->
        [','], vhdl_expression(Expr),
               vhdl_expression_list(Exprs).

Rule 36


vhdl_slice_name(vhdl_name(P,Range)) -->
       vhdl_prefix(P),
       ['('], !, vhdl_discrete_range(Range), [')'].

Rule 37


vhdl_attribute_name(vhdl_name(P,Sign,Attr,Expr)) -->
       vhdl_prefix(P),  vhdl_opt_signature(Sign),
       [ attr(Attr) ], !,  vhdl_opt_static_expression(Expr).

vhdl_opt_static_expression(Expr) -->
        ['('], vhdl_expression(Expr), [')'].

vhdl_opt_static_expression(null) --> [].

Rule 38


vhdl_function_call(vhdl_call(Call,Args)) -->
       vhdl_name(Call), vhdl_opt_association_list(Args).

Rule 39


vhdl_aggregate([A|As]) --> ['('],
        vhdl_element_association(A),
        vhdl_more_aggregate(As).

vhdl_more_aggregate([])     --> [')'], !.
vhdl_more_aggregate([A|As]) -->
        [','], vhdl_element_association(A),
        vhdl_more_aggregate(As).

Rule 40


vhdl_qualified_expression(qual_expr(Type,Expr)) -->
       vhdl_mark(Type), [ '''' ],
       vhdl_expression_or_aggregate(Expr).

vhdl_expression_or_aggregate(Expr) --> 
       [ '(' ],  vhdl_expression(Expr), [ ')' ].

vhdl_expression_or_aggregate(Ag) --> vhdl_aggregate(Ag).

Rule 41


vhdl_type_conversion(type_conversion(Type,Expr)) -->
       vhdl_mark(Type), ['('], vhdl_expression(Expr), [')'].

Rule 42


vhdl_allocator(A) --> [ new ], vhdl_alloc_subterm(A).

vhdl_alloc_subterm(A) --> vhdl_subtype_indication(A).
vhdl_alloc_subterm(A) --> vhdl_qualified_expression(A).

3.9 Operators

Rule 43


vhdl_boolop_associative(and)  --> [ and ].
vhdl_boolop_associative(or)   --> [ or ].
vhdl_boolop_associative(xor)  --> [ xor ].
vhdl_boolop_associative(xnor) --> [ xnor ].

vhdl_boolop_non_associative(nand) --> [ nand ].
vhdl_boolop_non_associative(nor)  --> [ nor ].

vhdl_relational_operator('=')    --> [ '=' ].
vhdl_relational_operator('/=')   --> [ '/=' ].
vhdl_relational_operator('<')    --> [ '<' ].
vhdl_relational_operator('>')    --> [ '>' ].
vhdl_relational_operator('<=')   --> [ '<=' ].
vhdl_relational_operator('>=')   --> [ '>=' ].

vhdl_shift_operator(sll)   --> [ sll ].
vhdl_shift_operator(srl)   --> [ srl ].
vhdl_shift_operator(sla)   --> [ sla ].
vhdl_shift_operator(sra)   --> [ sra ].
vhdl_shift_operator(rol)   --> [ rol ].
vhdl_shift_operator(ror)   --> [ ror ].

vhdl_adding_operator('+')   --> [ '+' ].
vhdl_adding_operator('-')   --> [ '-' ].
vhdl_adding_operator('&')   --> [ '&' ].

vhdl_sign('+')   --> [ '+' ].
vhdl_sign('-')   --> [ '-' ].

vhdl_multiplying_operator('*')   --> [ '*' ].
vhdl_multiplying_operator('/')   --> [ '/' ].
vhdl_multiplying_operator(mod)   --> [ mod ].
vhdl_multiplying_operator(rem)   --> [ rem ].

Rule 44


vhdl_operator(and).                  vhdl_operator(or).
vhdl_operator(xor).                  vhdl_operator(xnor).
vhdl_operator(nand).                 vhdl_operator(nor).

vhdl_operator('=').                  vhdl_operator('/=').
vhdl_operator('<').                  vhdl_operator('>').
vhdl_operator('<=').                 vhdl_operator('>=').

vhdl_operator(sll).                  vhdl_operator(srl).
vhdl_operator(sla).                  vhdl_operator(sra).
vhdl_operator(rol).                  vhdl_operator(ror).

vhdl_operator('+').                  vhdl_operator('-').
vhdl_operator('&').

vhdl_operator('*').                  vhdl_operator('/').
vhdl_operator(mod).                  vhdl_operator(rem).

3.10 Element Association and Choices

Rule 45


vhdl_element_association(element_association(C,Expr)) -->
       opt_vhdl_choices(C), vhdl_expression(Expr).

opt_vhdl_choices(C)    --> vhdl_choices(C), ['=>'], !.
opt_vhdl_choices(null) --> [].

Rule 46


vhdl_choices([C|Cs]) -->
        ( vhdl_choice(C), !
        ; { parse_error('choices') } ),
        vhdl_more_choices(Cs).

vhdl_more_choices([C|Cs]) --> ['|'], !,
       vhdl_choice(C),  vhdl_more_choices(Cs).
vhdl_more_choices([]) --> [].

The rule for vhdl_choices//1 is a good example of how we can make the grammar more efficient by having one rule for the first item in a series and a second rule for the (possibly null) continuation of the series. Note that presence of the vertical bar determines the rule for vhdl_more_choices//1 . A more intuitive, but much less efficient grammar might use the following rules:


slow_vhdl_choices([C|Cs]) -->
        vhdl_choice(C), ['|'], slow_vhdl_choices(Cs).

slow_vhdl_choices([C]) -->
        vhdl_choice(C).

The problem with this is that vhdl_choice//1 can be an arbitrarily complex expression. Every time vhdl_choices is used, there will be one expression which is completely parsed twice, once before realizing that it is not followed by a vertical bar and then once again because it is the last (or only) choice.

Rule 47


vhdl_choice(others) --> [others], !.
vhdl_choice(C)      --> vhdl_discrete_range(C).
vhdl_choice(C)      --> vhdl_expression(C).

3.11 Type Declarations

Rule 48


vhdl_type_declaration(vhdl_type(ID,Def)) -->
         [type], vhdl_identifier(ID),
         ( [is], !,  vhdl_type_definition(ID,Def) 
         ; { Def = null } ).

Rule 49


vhdl_type_definition(_,Def) -->
         vhdl_enumeration_type_definition(Def).
vhdl_type_definition(_,Range) -->
         vhdl_range_constraint(Range).
vhdl_type_definition(ID,Physical) -->
         vhdl_physical_type_definition(ID,Physical).
vhdl_type_definition(_,Array) -->
         vhdl_unconstrained_array_definition(Array).
vhdl_type_definition(_,Array) -->
         vhdl_constrained_array_definition(Array).
vhdl_type_definition(ID,RType) -->
         vhdl_record_type_definition(ID,RType).
vhdl_type_definition(_,Access) -->
         vhdl_access_type_definition(Access).
vhdl_type_definition(_,FileType) -->
         vhdl_file_type_definition(FileType).

Rule 50


vhdl_enumeration_type_definition([E|Enums]) -->
        ['('], vhdl_enumeration_literal(E),
        vhdl_enumeration_literal_list(Enums).

vhdl_enumeration_literal_list([])     --> [')'], !.
vhdl_enumeration_literal_list([E|Es]) -->
        [','], vhdl_enumeration_literal(E),
        vhdl_enumeration_literal_list(Es).

Rule 51


vhdl_physical_type_definition(ID,vhdl_type(Range,Base,Secondary)) -->
        vhdl_range_constraint(Range),
        [ units ], 
          vhdl_base_unit_declaration(Base),
          vhdl_secondary_unit_declarations(Secondary),
        [end, units], 
        ([ ID ], ! ; []).

vhdl_secondary_unit_declarations([S|Ss]) -->
        vhdl_secondary_unit_declaration(S),
        vhdl_secondary_unit_declarations(Ss).

vhdl_secondary_unit_declarations([]) --> [].

Rule 52


vhdl_base_unit_declaration(ID) --> vhdl_identifier(ID).

Rule 53


vhdl_secondary_unit_declaration(vhdl_sec(ID,PL)) -->
        vhdl_identifier(ID),   ['='],
        vhdl_physical_literal(PL).

Rule 54


vhdl_unconstrained_array_definition(vhdl_array([ISD|ISDs],SI)) -->
        [array, '('],
             vhdl_index_subtype_definition(ISD),
             vhdl_index_subtype_definitions(ISDs),
        [of], vhdl_subtype_indication(SI).

vhdl_unconstrained_nature_definition(vhdl_nature_array([ISD|ISDs],SI)) -->
        [array, '('],
             vhdl_index_subtype_definition(ISD),
             vhdl_index_subtype_definitions(ISDs),
        [of], vhdl_subnature_indication(SI).

vhdl_index_subtype_definitions([]) --> [')'],!.

vhdl_index_subtype_definitions([I|Is]) -->
        [','], vhdl_index_subtype_definition(I),
        vhdl_index_subtype_definitions(Is).

Rule 55


vhdl_index_subtype_definition(TM) -->
        vhdl_mark(TM), [range,'<>'].  

Rule 56


vhdl_constrained_array_definition(vhdl_array(IC,SI)) -->
        [array], vhdl_index_constraint(IC),
        [of], vhdl_subtype_indication(SI).

vhdl_constrained_nature_definition(vhdl_nature_array(IC,SI)) -->
        [array], vhdl_index_constraint(IC),
        [of], vhdl_subnature_indication(SI).

Rule 57


vhdl_record_type_definition(ID,record([E|EDs])) -->
       [ record ],
       ( (vhdl_element_declaration(E),  vhdl_get_more, !)
       ; { parse_error('record field') } ),
        vhdl_element_declarations(EDs),
       [ end, record ],
       ([ ID ], ! ; []).

Rule 57.5


vhdl_record_nature_definition(ID,record([E|EDs])) -->
       [ record ],
       ( (vhdl_nature_element_declaration(E),  vhdl_get_more, !)
       ; { parse_error('record field') } ),
        vhdl_nature_element_declarations(EDs),
       [ end, record ],
       ([ ID ], ! ; []).

Rule 58


vhdl_element_declaration(vhdl_element(Is,SI)) -->
       vhdl_identifier_list_LA(Is),   [':'],
       vhdl_subtype_indication(SI).

vhdl_element_declarations([E|Es]) -->
       vhdl_element_declaration(E),
       vhdl_get_more,   !,
       vhdl_element_declarations(Es).

vhdl_element_declarations([],L,L).

Rule 58.5


vhdl_nature_element_declaration(vhdl_nature_element(Is,SI)) -->
       vhdl_identifier_list_LA(Is),   [':'],
       vhdl_subnature_indication(SI).

vhdl_nature_element_declarations([E|Es]) -->
       vhdl_nature_element_declaration(E),
       vhdl_get_more,   !,
       vhdl_nature_element_declarations(Es).

vhdl_nature_element_declarations([],L,L).

Rule 59


vhdl_access_type_definition(vhdl_access(TD)) -->
       [access], vhdl_subtype_indication(TD).

Rule 60


vhdl_file_type_definition(vhdl_filetype(Type)) -->
       [ file, of ], vhdl_mark(Type).

3.12 Subtypes and Constraints

Rule 61


vhdl_subtype_declaration(vhdl_subtype(ID,TD)) -->
       [ subtype ], vhdl_identifier(ID),
       [is], vhdl_subtype_indication(TD).

Rule 62


vhdl_subtype_indication(vhdl_subtype(FM,TM,C,TA))-->
       vhdl_opt_mark(FM),
       vhdl_mark(TM),
       vhdl_opt_constraint(C),
       vhdl_opt_tolerance_aspect(TA).

Rule 63


vhdl_opt_constraint(C)    --> vhdl_constraint(C).
vhdl_opt_constraint(null) --> [].

vhdl_constraint(R) --> vhdl_range_constraint(R).
vhdl_constraint(I) --> vhdl_index_constraint(I).

Rule 64


vhdl_range_constraint(S) -->                  
       [range], vhdl_range_specification(S).

Rule 65

Once again, if we lead with the test for the close parenthesis ( ')' ) we can save re-parsing the final discrete-range element.


vhdl_index_constraint(index([R|Rs])) -->
       ['('], vhdl_discrete_range(R),
              vhdl_more_discrete_ranges(Rs).

vhdl_more_discrete_ranges([]) --> [')'], !.
vhdl_more_discrete_ranges([R|Rs]) -->
        [','], vhdl_discrete_range(R), vhdl_more_discrete_ranges(Rs).

Rule 66


vhdl_discrete_range(R) --> vhdl_range_specification(R).

vhdl_discrete_range(R) --> vhdl_subtype_indication(R).

Rule 67

For the range specification below, the grammar in VHDL: Hardware Description and Design does not include the rule for an indexed name followed by an optional static expression. However, I have found examples of VHDL which seem to require this. In any case, this rule should be viewed with suspicion!


vhdl_range_specification(vhdl_range(E1,D,E2)) -->
       vhdl_simple_expression(E1), 
       vhdl_direction(D), 
       vhdl_simple_expression(E2).

vhdl_range_specification(vhdl_range(vhdl_name(P,Exprs,range),SE)) -->
       vhdl_indexed_name(vhdl_name(P,Exprs,[range])),     % !,
       vhdl_opt_static_expression(SE).

vhdl_range_specification(vhdl_range(TM,Sign,SE)) -->
       ( vhdl_mark(TM) ; vhdl_function_call(TM) ), 
       vhdl_opt_signature(Sign),
       [ attr(range) ],                                   % !, 
       vhdl_opt_static_expression(SE).

Rule 68


vhdl_direction(to)     --> [to].
vhdl_direction(downto) --> [downto].

3.125 Natures, Subnatures, Terminals, and Quantities

This section deals with rules added to VHDL due to VHDL-AMS extension.

Rule 68.1


vhdl_nature_declaration(vhdl_nature(Id,Def)) --> 
       [nature], vhdl_identifier(Id), [is],
       vhdl_nature_definition(Id,Def).

vhdl_nature_definition(_,scalar(Across,Through)) --> 
          vhdl_mark(Across), [across],
          vhdl_mark(Through), [through].
vhdl_nature_definition(_,Array) -->
         vhdl_unconstrained_nature_definition(Array).
vhdl_nature_definition(_,Array) -->
         vhdl_constrained_nature_definition(Array).
vhdl_nature_definition(ID,RType) -->
         vhdl_record_nature_definition(ID,RType).

vhdl_subnature_declaration(vhdl_subnature(Id,Ind)) --> 
       [subnature], vhdl_identifier(Id), [is],
       vhdl_subnature_indication(Ind).

vhdl_subnature_indication(vhdl_subnature_indication(Id,Cons,Tol)) --> 
       vhdl_mark(Id), 
       vhdl_opt_index_constraint(Cons),
       vhdl_opt_tolerance_across_through(Tol).

vhdl_opt_index_constraint(Cons) -->
       vhdl_index_constraint(Cons), !.
vhdl_opt_index_constraint(null) --> [].

vhdl_opt_tolerance_across_through(tolerance(A,T)) -->
       [ tolerance ], !, 
       vhdl_expression(A), [ across ],
       vhdl_expression(T), [ through ].

vhdl_opt_tolerance_across_through(null) --> [].

Rule 68.3


vhdl_terminal_declaration(terminal(Ids,Sn)) -->
                [terminal],
                vhdl_identifier_list(Ids), [':'],
                vhdl_subnature_indication(Sn).

vhdl_quantity_declaration(DI) --> 
                [quantity], 
                ( vhdl_free_quantity_declaration(DI) ;
                  vhdl_branch_quantity_declaration(DI) ;
                  vhdl_source_quantity_declaration(DI)
                ).

vhdl_free_quantity_declaration(free_quantity(IDs,Type,Expr)) -->
                vhdl_identifier_list(IDs), [':'],
                vhdl_subtype_indication(Type),
                vhdl_opt_assignment(Expr).

vhdl_branch_quantity_declaration(branch_quantity(AA,THA,TEA)) -->
                vhdl_opt_across_aspect(AA),
                vhdl_opt_through_aspect(THA),
                vhdl_terminal_aspect(TEA).

vhdl_source_quantity_declaration(source_quantity(IDs,Type,SA)) -->
                vhdl_identifier_list(IDs), [':'],
                vhdl_subtype_indication(Type),
                vhdl_source_aspect(SA).

The ID parameter is used to match the optional record name at the end of the declaration.

3.127 Through, Across, Source, Terminal, and Tolerance Aspects

This section deals with rules added to VHDL due to the VHDL-AMS extension.

Rule 68.5



vhdl_opt_across_aspect(AA) -->
	        vhdl_across_aspect(AA), !.
vhdl_opt_across_aspect(null) --> [].

vhdl_across_aspect(across_aspect(IDs, TA, Expr)) -->
	        vhdl_identifier_list(IDs), 
                vhdl_opt_tolerance_aspect(TA),
	        vhdl_opt_assignment(Expr),
                [across].

vhdl_opt_through_aspect(AA) -->
	        vhdl_through_aspect(AA), !.
vhdl_opt_through_aspect(null) --> [].

vhdl_through_aspect(through_aspect(IDs, TA, Expr)) -->
	        vhdl_identifier_list(IDs), 
                vhdl_opt_tolerance_aspect(TA),
	        vhdl_opt_assignment(Expr),
                [through].

vhdl_opt_source_aspect(SA) -->
	        vhdl_source_aspect(SA), !.
vhdl_opt_source_aspect(null) --> [].

vhdl_source_aspect(spectrum_aspect(Mag, Phase)) -->
	        [spectrum], 
                vhdl_simple_expression(Mag), [','],
	        vhdl_simple_expression(Phase).

vhdl_source_aspect(noise_aspect(Mag)) -->
	        [noise], 
	        vhdl_simple_expression(Mag).

vhdl_opt_terminal_aspect(TA) -->
	        vhdl_terminal_aspect(TA), !.
vhdl_opt_terminal_aspect(null) --> [].

vhdl_terminal_aspect(terminal_aspect(N1,N2)) -->
                vhdl_name(N1), (  ([ to ], !, vhdl_name(N2))
                                ; { N2 = null }).
vhdl_opt_tolerance_aspect(TA) -->
	        vhdl_tolerance_aspect(TA), !.
vhdl_opt_tolerance_aspect(null) --> [].

vhdl_tolerance_aspect(tolerance_aspect(Expr)) -->
                [tolerance],
                vhdl_expression(Expr).

3.13 Objects, Aliases, Files, Disconnections

The syntax of file declaration in VHDL-93 is now incompatible with that in VHDL-87.

Rule 69


vhdl_constant_declaration(DI) -->
                vhdl_object_declaration(constant,DI).
vhdl_signal_declaration(DI) -->
                vhdl_object_declaration(signal,DI).
vhdl_ordinary_variable_declaration(DI) -->
                vhdl_object_declaration(variable,DI).
vhdl_shared_variable_declaration(DI) -->
                vhdl_object_declaration(shared_variable,DI).

vhdl_object_declaration(DI) -->
                vhdl_object_declaration(_,DI).

vhdl_object_declaration(C,object_declaration(C,IDs,Type,Kind,Expr)) -->
                vhdl_object_class(C),
                vhdl_identifier_list(IDs), [':'],
                vhdl_subtype_indication(Type),
                vhdl_opt_signal_kind(Kind),
                vhdl_opt_assignment(Expr).

vhdl_opt_assignment(vhdl_assign(Expr)) -->
       [':='], !, vhdl_expression(Expr).

vhdl_opt_assignment(null) --> [].

Rule 70


vhdl_object_class(signal)   --> [signal],   !.
vhdl_object_class(constant) --> [constant], !.
vhdl_object_class(variable) --> [variable], !.
vhdl_object_class(shared_variable) --> [shared, variable], !.
vhdl_object_class(file)     --> [file], !.
vhdl_object_class(quantity)     --> [quantity], !.
vhdl_object_class(terminal)     --> [terminal], !.

vhdl_opt_object_class(Class) --> vhdl_object_class(Class), !.
vhdl_opt_object_class(null)  --> [].

Rule 71


vhdl_opt_signal_kind(bus)      --> [bus], !.
vhdl_opt_signal_kind(register) --> [register], !.
vhdl_opt_signal_kind(null)     --> [].

Rule 72


vhdl_alias_declaration(vhdl_alias(ID,Type,Name,Sign)) -->
       [alias], vhdl_alias_designator(ID), 
       ([':'], vhdl_subtype_indication(Type) ; {Type = null}),  
       [is], vhdl_name(Name),
       vhdl_opt_signature(Sign).


vhdl_alias_designator(ID)       --> vhdl_identifier(ID), !.
vhdl_alias_designator(char(L))  --> [ char(L) ], !.
vhdl_alias_designator(ST)       --> [string(SL)], !, { name(ST,SL) }.

Rule 73


vhdl_file_declaration(vhdl_file(IDs,SI,Mode,Se)) -->
       [ file ], 
          vhdl_identifier_list(IDs),
       [ ':' ],  vhdl_subtype_indication(SI),
          vhdl_opt_file_open_info(Mode,Se).

vhdl_opt_file_open_info(Mode,Se) -->
       vhdl_opt_file_open_kind(Mode), 
      ( [ is ], vhdl_expression(Se)  ; { Se = null } ).        
%     ( [ is ], !, [ string(Se) ]  ; { Se = null } ).        

vhdl_opt_file_open_kind(Mode) -->
       [ open ], !, vhdl_file_mode(Mode).
vhdl_opt_file_open_kind(null) --> [ ].

vhdl_file_mode(read_mode) --> [read_mode], !.
vhdl_file_mode(write_mode) --> [write_mode], !.
vhdl_file_mode(append_mode) --> [append_mode], !.

vhdl_file_mode(Mode) --> 
        vhdl_opt_mode(Mode), !, 
        { write('WARNING: File mode incompatible with VHDL-93'), nl }.

vhdl_file_mode(Mode) --> vhdl_expression(Mode), !.

vhdl_file_mode(_) --> { parse_error('file opening mode') }.

Rule 74


vhdl_disconnection_specification(disconnect_spec(SL,Type,Time)) -->
       [ disconnect ],
          vhdl_signal_list(SL), [':'], vhdl_mark(Type),
       [ after ], vhdl_expression(Time).

Rule 75


vhdl_signal_list(all)    --> [all], !.
vhdl_signal_list(others) --> [others], !.
vhdl_signal_list([S|Ss]) -->
        vhdl_name(S),  !,   vhdl_signal_list_aux(Ss).
vhdl_signal_list([ ])    --> { parse_error('signal list') }.

vhdl_signal_list_aux([S|Ss]) -->
        [','], !, vhdl_name(S), vhdl_signal_list(Ss).
vhdl_signal_list_aux([ ])    --> [ ].

3.14 Signatures

The signatures have been introduced in VHDL-93 to distinguish between overloaded subprograms and overloaded enumeration literals.

Rule 75

.5

vhdl_opt_mark_list([ID|IDs]) -->
        vhdl_mark(ID), !,
        ( [','], !, vhdl_opt_mark_list(IDs)
        ; { IDs = [] } ).

vhdl_opt_mark_list([]) --> [ ].
 
vhdl_opt_signature(signature(Ids,Id)) --> 
          ['['], !,  vhdl_opt_mark_list(Ids),
          ( [ return ], !, vhdl_mark(Id)  ; { Id = null } ),  [']'].

vhdl_opt_signature(null) --> [].

3.15 Attribute Declarations and Specifications

Rule 76


vhdl_attribute_declaration(attribute_declaration(ID,Type)) -->
       [ attribute ],
       vhdl_identifier(ID), [ ':' ], vhdl_mark(Type).

Rule 77


vhdl_attribute_specification(attr_spec(ID,Entity,Expr)) -->
       [ attribute ],  vhdl_identifier(ID), 
       [ of ],  vhdl_entity_specification(Entity), [ is ],
       vhdl_expression(Expr).

Rule 78


vhdl_entity_specification(entity_spec(Names,Class)) -->
       vhdl_entity_name_list(Names), [':'], vhdl_entity_class(Class).

Rule 79


vhdl_entity_name_list(all)    --> [ all ], !.
vhdl_entity_name_list(others) --> [ others ],!.
vhdl_entity_name_list([D|Ds]) -->
       vhdl_entity_designator(D), !, vhdl_entity_name_list_aux(Ds).
vhdl_entity_name_list([]) -->
       { parse_error('entity name list') }.

vhdl_entity_name_list_aux([D|Ds]) -->
       [','], !, vhdl_entity_designator(D), vhdl_entity_name_list_aux(Ds).
vhdl_entity_name_list_aux([])     --> [ ].

vhdl_entity_designator(tag_sign(T,S)) -->    
        vhdl_entity_tag(T), vhdl_opt_signature(S).

vhdl_entity_tag(T)        -->    vhdl_designator(T).
vhdl_entity_tag(char(L))  -->    [ char(L) ].

Rule 80


vhdl_entity_class(entity)       --> [ entity ], !.
vhdl_entity_class(architecture) --> [ architecture ], !.
vhdl_entity_class(configuration)--> [ configuration ], !.
vhdl_entity_class(procedure)    --> [ procedure ], !.
vhdl_entity_class(function)     --> [ function ], !.
vhdl_entity_class(package)      --> [ package ], !.
vhdl_entity_class(type)         --> [ type ], !.
vhdl_entity_class(subtype)      --> [ subtype ], !.
vhdl_entity_class(constant)     --> [ constant ], !.
vhdl_entity_class(signal)       --> [ signal ], !.
vhdl_entity_class(variable)     --> [ variable ], !.
vhdl_entity_class(component)    --> [ component ], !.
vhdl_entity_class(label)        --> [ label ], !.
vhdl_entity_class(literal)      --> [ literal ], !.
vhdl_entity_class(units)        --> [ units ], !.
vhdl_entity_class(group)        --> [ group ], !.
vhdl_entity_class(file)         --> [ file ], !.
vhdl_entity_class(nature)       --> [ nature ], !.
vhdl_entity_class(subnature)    --> [ subnature ], !.
vhdl_entity_class(quantity)     --> [ quantity ], !.
vhdl_entity_class(terminal)     --> [ terminal ], !.

3.16 Schemes

Rule 81


vhdl_generation_scheme(S) --> vhdl_if_scheme(S), !.
vhdl_generation_scheme(S) --> vhdl_for_scheme(S).

Rule 82


vhdl_iteration_scheme(S) --> vhdl_for_scheme(S), !.
vhdl_iteration_scheme(S) --> vhdl_while_scheme(S).

vhdl_opt_iteration_scheme(S)    --> vhdl_iteration_scheme(S).
vhdl_opt_iteration_scheme(null) --> [].

Rule 83


vhdl_if_scheme(if(Expr)) --> [ if ], vhdl_expression(Expr).

Rule 84


vhdl_for_scheme(for(ID,Range)) -->
        [ for ], vhdl_identifier(ID),
        [  in ], vhdl_discrete_range(Range).

Rule 85


vhdl_while_scheme(while(Expr)) --> [ while ], vhdl_expression(Expr).

3.17 Concurrent Statements

Rule 86


vhdl_entity_concurrent_statements([S|Ss]) -->
        vhdl_entity_concurrent_statement(S),
        vhdl_get_more,   !,
        vhdl_entity_concurrent_statements(Ss).

vhdl_entity_concurrent_statements([]) --> [].

vhdl_concurrent_statements([S|Ss]) -->
        vhdl_concurrent_statement(S),
        vhdl_get_more,   !,
        vhdl_concurrent_statements(Ss).

vhdl_concurrent_statements([]) --> [].

Rule 87


vhdl_entity_concurrent_statement(S) -->
          vhdl_concurrent_assertion_statement(S).
vhdl_entity_concurrent_statement(S) -->
          vhdl_concurrent_procedure_call(S).
vhdl_entity_concurrent_statement(S) -->
          vhdl_process_statement(S).

vhdl_concurrent_statement(null) --> [trace], {trace}.
vhdl_concurrent_statement(S) -->
          vhdl_block_statement(S).
vhdl_concurrent_statement(S) -->
          vhdl_concurrent_assertion_statement(S).
vhdl_concurrent_statement(S) -->
          vhdl_concurrent_procedure_call(S).
vhdl_concurrent_statement(S) -->
          vhdl_component_instantiation_statement(S).
vhdl_concurrent_statement(S) --> 
          vhdl_concurrent_signal_assignment_statement(S).
vhdl_concurrent_statement(S) -->
          vhdl_generate_statement(S).
vhdl_concurrent_statement(S) -->
          vhdl_process_statement(S).
vhdl_concurrent_statement(S) -->
          vhdl_concurrent_break_statement(S).
vhdl_concurrent_statement(S) -->
          vhdl_simultaneous_statement(S).
%          vhdl_simultaneous_statement_part(S).

Refer to Rule 105 for an explanation of trace.

Rule 88


vhdl_block_statement(block(ID,Expr,GIL,GAL,PIL,PAL,ODI,Ss)) -->
        vhdl_identifier(ID), [ ':', block ],
           vhdl_opt_paren_expression(Expr),
           ( [ is ], ! ; [ ] ),
           vhdl_opt_generic(GIL,GAL),
           vhdl_opt_port(PIL,PAL),
           vhdl_opt_declarative_items(block,ODI),
        [ begin ],
           vhdl_concurrent_statements(Ss),
        [ end, block ], vhdl_opt_identifier(ID).

vhdl_opt_generic(GIL,GAL) -->
           vhdl_generic_statement(GIL),
           vhdl_opt_generic_map_statement(GAL),
        vhdl_opt_get_more.
vhdl_opt_generic(null,null) --> [].

vhdl_generic_statement(IL) -->
        [ generic ], !, vhdl_interface_list(IL),
        vhdl_get_more.

vhdl_opt_port(PIL,PAL) -->
           vhdl_port_statement(PIL),
           vhdl_opt_port_map_statement(PAL),
        vhdl_opt_get_more.
vhdl_opt_port(null,null) --> [].

vhdl_port_statement(IL) -->
        [ port ], !, vhdl_interface_list(IL),
        vhdl_get_more.

Note that the use of keyword is is more consistent in VHDL-93 compared to VHDL-87. See also vhdl_process_statement and vhdl_component_declaration.

Rule 89


vhdl_component_instantiation_statement(comp_instant(ID,IU,AL1,AL2)) -->
        vhdl_identifier(ID), [ ':' ],  vhdl_instantiated_unit(IU),
        vhdl_opt_generic_map_statement(AL1),
        vhdl_opt_port_map_statement(AL2).

Rule 89a


vhdl_instantiated_unit(comp(CM)) --> 
        ([ component ], ! ; [ ]), vhdl_mark(CM).

vhdl_instantiated_unit(entity(EID,AID)) --> 
        [ entity ], !, vhdl_mark(EID), 
        ( [ '(' ], !, vhdl_identifier(AID), [ ')' ] 
        ; { AID = null } ).

vhdl_instantiated_unit(config(CID)) --> 
        [ configuration ], !, vhdl_mark(CID).

Rule 90


vhdl_concurrent_assertion_statement(concurrent_assertion(ID,Post,Stmt)) -->
       vhdl_opt_label(ID), vhdl_opt_postponed(Post),
       vhdl_assertion_statement(Stmt).

vhdl_opt_postponed(postponed)   --> [ postponed ], !.
vhdl_opt_postponed(null)        --> [ ].

Rule 91


vhdl_concurrent_procedure_call(cpc(ID,Post,S)) -->
       vhdl_opt_label(ID), vhdl_opt_postponed(Post),
       vhdl_procedure_call_statement(S).

Rule 92


vhdl_concurrent_signal_assignment_statement(csas(ID,Post,CSAS)) -->
        vhdl_opt_label(ID), vhdl_opt_postponed(Post),
        vhdl_conditional_signal_assignment(CSAS).
vhdl_concurrent_signal_assignment_statement(ssas(ID,Post,CSAS)) -->
        vhdl_opt_label(ID), vhdl_opt_postponed(Post),
        vhdl_selected_signal_assignment_statement(CSAS).

Rule 93


vhdl_conditional_signal_assignment(csa(T,G,RT,Tr,W)) -->
       vhdl_target(T), ['<='],
       vhdl_opt_delay_mechanism(G,RT,Tr), vhdl_conditional_waveforms(W).

Rule 94


vhdl_conditional_waveforms([wave(W,Cond)|Ws]) -->
        vhdl_waveform(W), 
        vhdl_opt_conditional_waveforms(Cond,Ws).

vhdl_opt_conditional_waveforms(Expr,Ws) -->
       [ when ], !, vhdl_expression(Expr),
       ( [ else ], !,  vhdl_conditional_waveforms(Ws)
       ; { Ws = [] } ).

vhdl_opt_conditional_waveforms(null,[]) --> [].

Rule 95


vhdl_waveform(unaffected) --> [ unaffected ], !.

vhdl_waveform([WE|WEs]) -->
       vhdl_waveform_element(WE), vhdl_opt_waveforms(WEs).

vhdl_opt_waveforms([WE|WEs]) -->
       [','], !, vhdl_waveform_element(WE), vhdl_opt_waveforms(WEs).
vhdl_opt_waveforms([]) --> [].

Rule 96


vhdl_waveform_element(event(null,Time)) -->
       [ null ], !, vhdl_opt_delay(Time).
vhdl_waveform_element(event(Expr,Time)) -->
       vhdl_expression(Expr), vhdl_opt_delay(Time).

vhdl_opt_delay(Time) --> [ after ], !, vhdl_expression(Time).
vhdl_opt_delay(null) --> [].

Rule 97


vhdl_target(N) --> vhdl_name(N).
vhdl_target(A) --> vhdl_aggregate(A).

Rule 98


vhdl_opt_delay_mechanism(guarded,RT,TM)       --> 
                    [  guarded  ], !, vhdl_opt_delay_mechanism(_,RT,TM).
vhdl_opt_delay_mechanism(null,null,transport) --> 
                    [ transport ], !.
vhdl_opt_delay_mechanism(null,RT,inertial)    --> 
                    ( [ reject ], !, vhdl_expression(RT) ; { RT = null } ),
                      [ inertial ], !.
vhdl_opt_delay_mechanism(null,null,null)    -->  [ ].

Rule 99


vhdl_selected_signal_assignment_statement(selected(Expr,Target,G,RT,T,Ws)) -->
        [ with ], vhdl_expression(Expr), [ select ],
        vhdl_target(Target),
        ['<='], vhdl_opt_delay_mechanism(G,RT,T), 
	vhdl_selected_waveforms(Ws).

Rule 100


vhdl_selected_waveform(vhdl_waveform(W,Cs)) -->
        vhdl_waveform(W), [ when ], vhdl_choices(Cs).

vhdl_selected_waveforms([SW|SWs]) -->
        vhdl_selected_waveform(SW),
        vhdl_additional_selected_waveforms(SWs).

vhdl_selected_waveforms([]) --> { parse_error('selected waveform') }.

vhdl_additional_selected_waveforms(SWs) -->
         [','], !, vhdl_selected_waveforms(SWs).

vhdl_additional_selected_waveforms([]) --> [].

Rule 101

The following clause introduces one of the few replacements in VHDL clauses due to VHDL-AMS extension. However, there is a small error in the LRM-97 because it refers to the nonterminal architecture_statement but does not define it. Instead, it defines the nonterminal architecture_statement_part which is essentially a sequence of concurrent_statement.

vhdl_generate_statement(generate(ID,Scheme,DI,Ss)) -->
        vhdl_identifier(ID),  [':'],
           vhdl_generation_scheme(Scheme), [ generate ],
           ( vhdl_opt_declarative_items(block,DI), [ begin ], !
           ; { DI = null } ),
           vhdl_concurrent_statements(Ss),
%           vhdl_architecture_statements(Ss),
        [ end, generate ], vhdl_opt_identifier(ID).

Rule 102


vhdl_process_statement(vhdl_process(LID,ID,Post,SL,DI,Ss)) -->
        vhdl_opt_label(LID), vhdl_opt_postponed(Post),
        [ process ], vhdl_opt_sensitivity_list(SL), 
        ( [ is ], ! ; [ ] ),
        vhdl_opt_declarative_items(process,DI),
        [ begin ],     
          vhdl_sequential_statements(Ss),
        [ end ], 
        ( { Post == postponed }, [ postponed ], ! ; [] ),
        [process ], vhdl_opt_label_use(LID,ID).

vhdl_opt_label(LID)   --> vhdl_identifier(LID), [':'], !.
vhdl_opt_label(null) --> [].

vhdl_opt_label_use(LID,ID)   --> 
         vhdl_identifier(ID), !,
        {(LID == ID) -> true  ; parse_error('optional label use')}.
vhdl_opt_label_use(_,null) --> [].
% This fails if the used label is different from the declared label.

Rule 103


vhdl_sensitivity_list([S|Ss]) -->
        vhdl_name(S),
        ( ( [','], !, vhdl_sensitivity_list(Ss) ) ; { Ss = [ ] } ).

vhdl_sensitivity_list([ ]) --> [ ].

vhdl_opt_sensitivity_list([S|SL]) --> 
        ['('], vhdl_sensitivity_list([S|SL]), [')'].
vhdl_opt_sensitivity_list([]) --> [].

The cut cannot be placed immediately after vhdl_name in the first clause because it destructively interferes with backtracking.

Rule 103.5

This clause is an VHDL-AMS addition.

vhdl_concurrent_break_statement(vhdl_concurrent_break(ID,BL,SC,WC)) -->
         vhdl_opt_label(ID), 
         [ break ], vhdl_opt_break_list(BL),
         vhdl_opt_sensitivity_clause(SC),
         vhdl_opt_when_condition(WC).
 
vhdl_opt_sensitivity_clause(vhdl_sensitivity_clause(SL)) -->
         [ on ], !, vhdl_sensitivity_list(SL).
vhdl_opt_sensitivity_clause(null) --> [].

3.18 Sequential Statements

When more than one semi-colon terminated statement is part of a production, we must call vhdl_get_more//0 to read more tokens.

Rule 104


vhdl_sequential_statements([S|Ss]) -->
        vhdl_sequential_statement(S),
        vhdl_get_more,    !,
        vhdl_sequential_statements(Ss).

vhdl_sequential_statements([]) --> [].

Rule 105

Before giving the proper definition of the sequential statement, we include a special rule for debugging. Debugging this grammar on large VHDL files will be problematic unless we have a way of signaling, from inside the text of the VHDL file, when we want to turn on tracing. To this end we will pretend that VHDL has a TRACE statement, consisting of the keyword trace followed by a semicolon. Whenever the parser encounters this special sequential statement, tracing will be turned on. The object returned to the parser will be the same as for the null statement. This clause, and the trace keyword, should probably be removed in a production version of the parser.


vhdl_sequential_statement(null) --> [trace], {trace}.
vhdl_sequential_statement(S) --> vhdl_assertion_statement(S).
vhdl_sequential_statement(S) --> vhdl_report_statement(S).
vhdl_sequential_statement(S) --> vhdl_case_statement(S).
vhdl_sequential_statement(S) --> vhdl_exit_statement(S).
vhdl_sequential_statement(S) --> vhdl_if_statement(S).
vhdl_sequential_statement(S) --> vhdl_loop_statement(S).
vhdl_sequential_statement(S) --> vhdl_next_statement(S).
vhdl_sequential_statement(S) --> vhdl_null_statement(S).
vhdl_sequential_statement(S) --> vhdl_procedure_call_statement(S).
vhdl_sequential_statement(S) --> vhdl_return_statement(S).
vhdl_sequential_statement(S) --> vhdl_signal_assignment_statement(S).
vhdl_sequential_statement(S) --> vhdl_variable_assignment_statement(S).
vhdl_sequential_statement(S) --> vhdl_wait_statement(S).
vhdl_sequential_statement(S) --> vhdl_break_statement(S).

Rule 106


vhdl_assertion_statement(assert(LID,Assertion,String,Severity)) -->
       vhdl_opt_label(LID), 
       [ assert ], !,  vhdl_expression(Assertion),
                       vhdl_opt_report(String),
                       vhdl_opt_severity(Severity).

vhdl_opt_report(R)      --> [ report ], !, vhdl_expression(R).
vhdl_opt_report(null)   --> [].

vhdl_opt_severity(S)    --> [ severity ], !, vhdl_expression(S).
vhdl_opt_severity(null) --> [].

Rule 106a


vhdl_report_statement(report(LID,String,Severity)) -->
             vhdl_opt_label(LID), 
              [report], !,
                    vhdl_expression(String),
                    vhdl_opt_severity(Severity).

Rule 107


vhdl_case_statement(case(LID,ID,Cond,Cases)) -->
       vhdl_opt_label(LID),
       [ case ], vhdl_expression(Cond), [ is ], !,
       vhdl_case_statement_alternatives(Cases),
       [ end, case ], vhdl_opt_label_use(LID,ID).

Rule 108


vhdl_case_statement_alternatives([vhdl_case(Choices,Ss)|Cases]) -->
       [ when ],  vhdl_choices(Choices), ['=>'], !,
       vhdl_sequential_statements(Ss),
       vhdl_case_statement_alternatives_aux(Cases).

vhdl_case_statement_alternatives([]) --> 
       { parse_error('case alternatives') }.

vhdl_case_statement_alternatives_aux([vhdl_case(Choices,Ss)|Cases]) -->
       [ when ],  vhdl_choices(Choices), ['=>'], !,
       vhdl_sequential_statements(Ss),
       vhdl_case_statement_alternatives_aux(Cases).

vhdl_case_statement_alternatives_aux([]) --> [].

Rule 109


vhdl_exit_statement(vhdl_exit(LID,ID,Expr)) -->
       vhdl_opt_label(LID),
       [ exit ], vhdl_opt_label_use(LID,ID),
       vhdl_opt_when_condition(Expr).

vhdl_opt_when_condition(Expr) -->
       [ when ], !,  vhdl_expression(Expr).
vhdl_opt_when_condition(null) --> [ ].

Rule 110


vhdl_if_statement(vhdl_if(LID,ID,Cond,Thens,Elses)) -->
       vhdl_opt_label(LID),
       [ if ], vhdl_expression(Cond), 
         [ then ], vhdl_sequential_statements(Thens),
         vhdl_else(LID,ID,Elses).

vhdl_else(LID,ID,elsif(ECond,Thens,Else)) -->
            [ elsif ], !,
               vhdl_expression(ECond),
             [ then ],
               vhdl_sequential_statements(Thens),
             vhdl_else(LID,ID,Else).

vhdl_else(LID,ID,Elses) -->
            [ else ], !, vhdl_sequential_statements(Elses),
            vhdl_end(LID,ID).

vhdl_else(LID,ID,[]) --> vhdl_end(LID,ID), !.

vhdl_end(LID,ID) --> [ end, if ], vhdl_opt_label_use(LID,ID).

Rule 111


vhdl_loop_statement(vhdl_loop(LID,ID,IScheme,Ss)) -->
        vhdl_opt_label(LID),
        vhdl_opt_iteration_scheme(IScheme),
        [ loop ],
          vhdl_sequential_statements(Ss),
        [ end, loop ], vhdl_opt_label_use(LID,ID).

Rule 112


vhdl_next_statement(vhdl_next(LID,ID,Expr)) -->
       vhdl_opt_label(LID),
       [ next ], vhdl_opt_label_use(LID,ID),
       vhdl_opt_when_condition(Expr).

Rule 113


vhdl_null_statement(null(LID)) --> 
      vhdl_opt_label(LID), [null].

Rule 114


vhdl_procedure_call_statement(vhdl_call(LID,PID,Args)) -->
       vhdl_opt_label(LID),
       vhdl_name(PID), vhdl_opt_association_list(Args).

Rule 115


vhdl_return_statement(return(LID,Expr)) -->
       vhdl_opt_label(LID),
       [ return ], vhdl_expression(Expr).

Rule 116


vhdl_signal_assignment_statement(signal(LID,T,RT,Mode,W)) -->
       vhdl_opt_label(LID),
       vhdl_target(T), ['<='],
       vhdl_opt_delay_mechanism(null,RT,Mode), vhdl_waveform(W).

Rule 117


vhdl_variable_assignment_statement(assign(LID,Var,Expr)) -->
       vhdl_opt_label(LID),
       vhdl_target(Var), [ ':=' ], vhdl_expression(Expr).

Rule 118


vhdl_wait_statement(vhdl_wait(LID,SL,Expr,Time)) -->
       vhdl_opt_label(LID),
       [ wait ],  vhdl_opt_on(SL),
       vhdl_opt_until(Expr),
       vhdl_opt_for_time(Time).

vhdl_opt_on(SL)      --> [ on ], !, vhdl_sensitivity_list(SL).
vhdl_opt_on(null)    --> [].

vhdl_opt_until(Expr) --> [ until ], !, vhdl_expression(Expr).
vhdl_opt_until(null) --> [].

vhdl_opt_for_time(Time) --> [ for ], !, vhdl_expression(Time).
vhdl_opt_for_time(0) --> [].

Rule 118.1

The break-rules are VHDL-AMS addition.

vhdl_break_statement(vhdl_break(LID,BL,Expr)) --> 
        vhdl_opt_label(LID), [ break ],
        vhdl_opt_break_list(BL),
        vhdl_opt_when_condition(Expr).

vhdl_opt_break_list(BL) --> 
        vhdl_break_list(BL), !.
vhdl_opt_break_list([]) --> [].

vhdl_break_list([ BE | BL ]) -->
        vhdl_break_element(BE), 
        ([ ',' ] ->  vhdl_break_list(BL) 
                  ;  {BL = []}).

vhdl_break_element(vhdl_break_element(SC,N,Expr)) -->
        vhdl_opt_break_selector_clause(SC),
        vhdl_name(N), [ '=>' ], vhdl_expression(Expr).

vhdl_opt_break_selector_clause(vhdl_break_selector(N)) -->
        [ for ], vhdl_name(N), [ use ], !.
vhdl_opt_break_selector_clause(null) --> [].

3.185 Simultaneous Statements

This section describes VHDL-AMS additions.

Rule 118.2


vhdl_simultaneous_statement_part(simultaneous([DI | DL])) --> 
                    vhdl_simultaneous_statement(DI), 
                    vhdl_get_more, !,
                    vhdl_simultaneous_statement_part(DL).
vhdl_simultaneous_statement_part([]) --> [].

vhdl_simultaneous_statement(SS) --> 
            vhdl_simple_simultaneous_statement(SS) 
         ;  vhdl_simultaneous_if_statement(SS) 
         ;  vhdl_simultaneous_case_statement(SS) 
         ;  vhdl_simultaneous_procedural_statement(SS) 
         ;  vhdl_simultaneous_null_statement(SS).

Rule 118.3


vhdl_simple_simultaneous_statement(vhdl_simple_simultaneous(LID,M,E1,E2,TA))  -->
            vhdl_opt_label(LID), 
            (   ([ pure ],   !, {M = pure})   ; 
                ([ impure ], !, {M = impure}) ; 
                ( { M = null } ) 
            ), 
            vhdl_simple_expression(E1), ['=='], 
            vhdl_simple_expression(E2), 
            vhdl_opt_tolerance_aspect(TA).

Rule 118.4



vhdl_simultaneous_case_statement(simultaneous_case(LID,ID,Cond,Cases)) -->
       vhdl_opt_label(LID),
       [ case ],  vhdl_expression(Cond), [ use ], !,
       vhdl_simultaneous_alternatives(Cases),
       [ end, case ], vhdl_opt_label_use(LID,ID).

vhdl_simultaneous_alternatives([vhdl_case(Choices,Ss)|Cases]) -->
       [ when ],  vhdl_choices(Choices), [ use ], !,
       vhdl_simultaneous_statement_part(Ss),
       vhdl_simultaneous_alternatives_aux(Cases).

vhdl_simultaneous_alternatives([]) --> 
       { parse_error('case alternatives') }.

vhdl_simultaneous_alternatives_aux([vhdl_case(Choices,Ss)|Cases]) -->
       [ when ],  vhdl_choices(Choices), [ use ], !,
       vhdl_simultaneous_statement_part(Ss),
       vhdl_simultaneous_alternatives_aux(Cases).

vhdl_simultaneous_alternatives_aux([]) --> [].

Rule 118.5



vhdl_simultaneous_if_statement(simultaneous_if(LID,ID,Cond,Thens,Elses)) -->
       vhdl_opt_label(LID),
       [ if ], vhdl_expression(Cond), 
         [ use ], vhdl_simultaneous_statement_part(Thens),
         vhdl_simultaneous_else(LID,ID,Elses).

vhdl_simultaneous_else(LID,ID,elsif(ECond,Thens,Else)) -->
            [ elsif ], !,
               vhdl_expression(ECond),
             [ use ],
               vhdl_simultaneous_statement_part(Thens),
             vhdl_simultaneous_else(LID,ID,Else).

vhdl_simultaneous_else(LID,ID,Elses) -->
            [ else ], !, vhdl_simultaneous_statement_part(Elses),
            vhdl_simultaneous_end(LID,ID).

vhdl_simultaneous_else(LID,ID,[]) --> vhdl_simultaneous_end(LID,ID), !.

vhdl_simultaneous_end(LID,ID) --> [ end, use ], vhdl_opt_label_use(LID,ID).

Rule 118.6


vhdl_simultaneous_procedural_statement(simultaneous_procedural(LID,ID,M,D,S))  -->
            vhdl_opt_label(LID),  
            (   ([ pure ],   !, {M = pure})   ; 
                ([ impure ], !, {M = impure}) ; 
                ( { M = null } ) 
            ), [ procedural ], ([ is ], ! ; [] ),
               vhdl_procedural_declarative_part(D), 
            [ begin], 
               vhdl_procedural_statement_part(S), 
            [ end, procedural ], 
               vhdl_opt_label_use(LID,ID).

Rule 118.7


vhdl_simultaneous_null_statement(simultaneous_null(LID))       -->
              vhdl_opt_label(LID), [null].

3.19 Components and Configurations

Rule 119


vhdl_component_declaration(vhdl_comp(ID,GIL,PIL)) -->
       [ component ], vhdl_identifier(ID), 
         ( [ is ], ! ; [ ] ),
         vhdl_opt_generic_statement(GIL),
         vhdl_opt_port_statement(PIL),
       [ end, component ], vhdl_opt_identifier(ID).

Rule 120


vhdl_block_configuration(vhdl_conf(Spec,Use,CI)) -->
       [ for ], vhdl_block_specification(Spec),
          vhdl_opt_use_clauses(Use),
          vhdl_opt_configuration_items(CI),
       [ end, for ],
       vhdl_get_more.

Rule 121


vhdl_block_specification(vhdl_name(ID,Index)) -->
       vhdl_mark(ID),
       ( [ '(' ], !, vhdl_index_specification(Index), [ ')' ]
       ; { Index = null } ).

Rule 122


vhdl_index_specification(Range) --> vhdl_discrete_range(Range).

vhdl_index_specification(Expr) --> vhdl_expression(Expr).

Rule 123


vhdl_opt_configuration_items([CI|CIs]) -->
                vhdl_configuration_item(CI), !,
                vhdl_opt_configuration_items(CIs).
vhdl_opt_configuration_items([]) --> [ ].

vhdl_configuration_item(BC) --> vhdl_block_configuration(BC).
vhdl_configuration_item(CC) --> vhdl_component_configuration(CC).

Rule 124


vhdl_component_configuration(vhdl_spec(CSpec,BI,Ss)) -->
       [ for ], vhdl_component_specification(CSpec),
                vhdl_opt_binding_indication(BI),
                vhdl_opt_get_more,
                ( vhdl_block_configuration(Ss), ! ; { Ss = null } ),
       [ end, for ],
       vhdl_get_more.

Rule 125


vhdl_configuration_specification(vhdl_spec(CSpec,BI)) -->
       [ for ], vhdl_component_specification(CSpec),
       vhdl_opt_binding_indication(BI).

Rule 126


vhdl_component_specification(spec(Spec,ID)) -->
       vhdl_instantiation_list(Spec), [':'], vhdl_mark(ID).

Rule 127


vhdl_instantiation_list(all)    --> [all], !.
vhdl_instantiation_list(others) --> [others], !.
vhdl_instantiation_list(IL)     --> vhdl_identifier_list(IL).

Rule 128


vhdl_opt_binding_indication(binding(EA,GAL,PAL)) -->
         vhdl_opt_entity_aspect(EA),
         vhdl_opt_generic_map_statement(GAL),
         vhdl_opt_port_map_statement(PAL).

vhdl_opt_generic_map_statement(IL) -->
        [ generic, map ], !,
        vhdl_association_list(IL).
vhdl_opt_generic_map_statement(null) --> [].

vhdl_opt_port_map_statement(IL) -->
        [ port, map ], !, 
        vhdl_association_list(IL).
vhdl_opt_port_map_statement(null) --> [].

Rule 129


vhdl_opt_entity_aspect(EA) -->
       [ use ], !, vhdl_entity_aspect(EA).

vhdl_opt_entity_aspect(null) --> [ ].

vhdl_entity_aspect(open) --> [open], !.

vhdl_entity_aspect(entity_aspect(CM,null)) -->
       [configuration], !, vhdl_mark(CM).

vhdl_entity_aspect(entity_aspect(Mark,ID)) -->
       [ entity],  vhdl_mark(Mark),
                   vhdl_opt_arch_identifier(ID).

vhdl_opt_arch_identifier(ID)   --> ['('], !, vhdl_identifier(ID), [')'].
vhdl_opt_arch_identifier(null) --> [].

3.20 Summary of Changes

We now highlight the revisions made to the original VHDL-87 parser to conform to the IEEE Standard 1076-1993 of VHDL, and then to the IEEE Standard 1076.1-1997 of VHDL. The changes roughly fall into three categories: cosmetic changes, extensions, and new additions. The cosmetic changes correspond to simple syntactic changes (without any semantic ramifications). The extensions refine the existing VHDL-87 constructs in some interesting way. The new additions correspond to newly introduced VHDL-93 and VHDL-AMS constructs. We also summarize updates and corrections made to the original parser.

Cosmetic changes

Extensions

Additions

Updates and Corrections

The original VHDL-87 parser assumed that the input VHDL-program is syntactically correct. So the parser actually permits programs that are syntactically incorrect according to LRM-87. (For example, consider the syntax of expressions.) Here we have tried to flag as error any departure from the syntax given in LRM-93. (However, the error message printed out by the parser is not very informative, and the parser is not robust.) The price we pay is a small increase in time required for parsing.

3.30 Porting to PC- Windows95 Environment

The PC-version of SWI-Prolog does not follow the standard convention used for path-names in the Windows environment. In particular, it uses forward slashes "/" instead of back slashes "\" as a file-separator. Thus, the query
?- exists_file('C:\Present')
fails while the following query succeeds
?- exists_file('C:/Present')
even when the file called Present is available in the directory C:\.

On UNIX, the command

pl -o vhdl_parser -c *.pl
creates the parser executable in the form of a self-starting state using the Unix "#!"-construct. In particular, the header information in the saved state looks as follows.
    #!/bin/sh
         #SAVE-VERSION=
         #PROLOG-VERSION=
         exec ${SWIPL-/path-to-emulator} -x $0 "$@"
                     ...
This is also the format of the generated file in the Windows environment, even though sh is not standard on PCs. So executing this saved state generates the bizzare error: Program is too big to fit in the memory. However, this problem can be remedied by using -x bootfile option as follows:

The tokenizer for VHDL requires two character look-ahead. The earlier versions of SWI-Prolog did not support peek_char , so we simulated it using stream_position/3 primitive. This simulation does not work in the Windows port of SWI-Prolog because it does not correctly handle the end-of-line . Fortunately, SWI-Prolog version 2.5.X supports peek_byte to remedy the problem.

There are subtle differences in range of constants that can be represented in the SPARC/Solaris 2.6 version and the PC/Windows95 version of the SWI-Prolog. For instance, a constant such as 10.0 E + 16 is acceptable on the UNIX version, but triggers an exception of the Windows95 version.

When the Java process dies, the associated Prolog process is automatically killed on UNIX, whereas the Prolog process can outlive the parent Java process on Windows 95. The strategy of explicitly invoking destroy() on InterruptedException does not work because the JVM intercepts the CNTL-c destined for the Java process.