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 by the first author to the VHDL-93 standard 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.
We have also collected all the changes made to the parser in a separate section at the end.
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.
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)}.
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).
We only have one kind of number at present which includes integers and floating point numbers.
vhdl_abstract_literal(F) --> [ number(F) ].
vhdl_enumeration_literal(char(L)) --> [ char(L) ], !. vhdl_enumeration_literal(ID) --> vhdl_identifier(ID).
vhdl_physical_literal(pl(AL,ID)) -->
vhdl_abstract_literal(AL), vhdl_mark(ID).
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([]) --> [].
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.
vhdl_design_unit(design_unit(CI,Unit)) -->
vhdl_opt_context_items(CI),
vhdl_library_unit(Unit).
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).
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).
vhdl_library_clause(library(IL)) -->
[ library ], vhdl_identifier_list(IL).
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([]) --> [].
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) --> [].
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).
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).
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).
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 .
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-93 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.
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) -->
{ 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).
VHDL-93 supports the concept of groups and group templates not present in VHDL-87.
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 } ).
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.
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.
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).
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).
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(_) --> [].
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).
vhdl_interface_element(interface_element(Class,IL,Mode,SubType,Bus,Expr)) -->
vhdl_opt_object_class(Class),
vhdl_identifier_list(IL), [':'],
vhdl_opt_mode(Mode),
vhdl_subtype_indication(SubType),
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(null,_,_,_).
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) --> [].
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([]) --> [].
vhdl_association_element(element(Formal,Actual)) -->
vhdl_opt_formal_part(Formal), vhdl_actual_part(Actual).
vhdl_formal_part(Name) --> vhdl_name(Name). vhdl_opt_formal_part(Name) --> vhdl_formal_part(Name), ['=>'], !. vhdl_opt_formal_part(null) --> [].
vhdl_actual_part(open) --> [ open ], !. vhdl_actual_part(Expr) --> vhdl_expression(Expr).
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-93 grammar closely.
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.
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 } ).
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).
vhdl_name(_) --> [N], { vhdl_keyword(N),!,fail }.
vhdl_name(attr_name([N,A|As])) -->
vhdl_designator(N), [attr(A)], !, vhdl_opt_attrs(As).
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([]) --> [].
vhdl_selected_name(vhdl_name(P,S)) -->
vhdl_prefix(P), ['.'], vhdl_suffix(S).
vhdl_prefix(_, [],_) :- !,fail.
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) --> [].
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).
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).
vhdl_slice_name(vhdl_name(P,Range)) -->
vhdl_prefix(P),
['('], !, vhdl_discrete_range(Range), [')'].
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) --> [].
vhdl_function_call(vhdl_call(Call,Args)) -->
vhdl_name(Call), vhdl_opt_association_list(Args).
vhdl_aggregate([A|As]) --> ['('],
vhdl_element_association(A),
vhdl_more_aggregate(As).
% ( vhdl_element_association(A), !
% ; { parse_error('aggregate element association') } ),
% vhdl_more_aggregate(As).
vhdl_more_aggregate([]) --> [')'], !.
vhdl_more_aggregate([A|As]) -->
[','], vhdl_element_association(A),
vhdl_more_aggregate(As).
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).
vhdl_type_conversion(type_conversion(Type,Expr)) -->
vhdl_mark(Type), ['('], vhdl_expression(Expr), [')'].
vhdl_allocator(A) --> [ new ], vhdl_alloc_subterm(A). vhdl_alloc_subterm(A) --> vhdl_subtype_indication(A). vhdl_alloc_subterm(A) --> vhdl_qualified_expression(A).
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 ].
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).
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) --> [].
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.
vhdl_choice(others) --> [others], !. vhdl_choice(C) --> vhdl_discrete_range(C). vhdl_choice(C) --> vhdl_expression(C).
vhdl_type_declaration(vhdl_type(ID,Def)) -->
[type], vhdl_identifier(ID),
( [is], !, vhdl_type_definition(ID,Def)
; { Def = null } ).
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).
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).
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([]) --> [].
vhdl_base_unit_declaration(ID) --> vhdl_identifier(ID).
vhdl_secondary_unit_declaration(vhdl_sec(ID,PL)) -->
vhdl_identifier(ID), ['='],
vhdl_physical_literal(PL).
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_index_subtype_definitions([]) --> [')'],!.
vhdl_index_subtype_definitions([I|Is]) -->
[','], vhdl_index_subtype_definition(I),
vhdl_index_subtype_definitions(Is).
vhdl_index_subtype_definition(TM) -->
vhdl_mark(TM), [range,'<>'].
vhdl_constrained_array_definition(vhdl_array(IC,SI)) -->
[array], vhdl_index_constraint(IC),
[of], vhdl_subtype_indication(SI).
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 ], ! ; []).
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).
vhdl_access_type_definition(vhdl_access(TD)) -->
[access], vhdl_subtype_indication(TD).
vhdl_file_type_definition(vhdl_filetype(Type)) -->
[ file, of ], vhdl_mark(Type).
vhdl_subtype_declaration(vhdl_subtype(ID,TD)) -->
[ subtype ], vhdl_identifier(ID),
[is], vhdl_subtype_indication(TD).
vhdl_subtype_indication(vhdl_subtype(FM,TM,C))-->
vhdl_opt_mark(FM),
vhdl_mark(TM),
vhdl_opt_constraint(C).
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).
vhdl_range_constraint(S) -->
[range], vhdl_range_specification(S).
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).
vhdl_discrete_range(R) --> vhdl_range_specification(R). vhdl_discrete_range(R) --> vhdl_subtype_indication(R).
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).
vhdl_direction(to) --> [to]. vhdl_direction(downto) --> [downto].
The syntax of file declaration in VHDL-93 is now incompatible with that in VHDL-87.
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) --> [].
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_opt_object_class(Class) --> vhdl_object_class(Class), !. vhdl_opt_object_class(null) --> [].
vhdl_opt_signal_kind(bus) --> [bus], !. vhdl_opt_signal_kind(register) --> [register], !. vhdl_opt_signal_kind(null) --> [].
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) }.
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') }.
vhdl_disconnection_specification(disconnect_spec(SL,Type,Time)) -->
[ disconnect ],
vhdl_signal_list(SL), [':'], vhdl_mark(Type),
[ after ], vhdl_expression(Time).
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([ ]) --> [ ].
The signatures have been introduced in VHDL-93 to distinguish between overloaded subprograms and overloaded enumeration literals.
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) --> [].
vhdl_attribute_declaration(attribute_declaration(ID,Type)) -->
[ attribute ],
vhdl_identifier(ID), [ ':' ], vhdl_mark(Type).
vhdl_attribute_specification(attr_spec(ID,Entity,Expr)) -->
[ attribute ], vhdl_identifier(ID),
[ of ], vhdl_entity_specification(Entity), [ is ],
vhdl_expression(Expr).
vhdl_entity_specification(entity_spec(Names,Class)) -->
vhdl_entity_name_list(Names), [':'], vhdl_entity_class(Class).
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) ].
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_generation_scheme(S) --> vhdl_if_scheme(S), !. vhdl_generation_scheme(S) --> vhdl_for_scheme(S).
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) --> [].
vhdl_if_scheme(if(Expr)) --> [ if ], vhdl_expression(Expr).
vhdl_for_scheme(for(ID,Range)) -->
[ for ], vhdl_identifier(ID),
[ in ], vhdl_discrete_range(Range).
vhdl_while_scheme(while(Expr)) --> [ while ], vhdl_expression(Expr).
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([]) --> [].
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).
Refer to rule 105 for an explanation of trace .
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 .
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).
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).
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) --> [ ].
vhdl_concurrent_procedure_call(cpc(ID,Post,S)) -->
vhdl_opt_label(ID), vhdl_opt_postponed(Post),
vhdl_procedure_call_statement(S).
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).
vhdl_conditional_signal_assignment(csa(T,G,RT,Tr,W)) -->
vhdl_target(T), ['<='],
vhdl_opt_delay_mechanism(G,RT,Tr), vhdl_conditional_waveforms(W).
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,[]) --> [].
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([]) --> [].
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) --> [].
vhdl_target(N) --> vhdl_name(N). vhdl_target(A) --> vhdl_aggregate(A).
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) --> [ ].
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).
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([]) --> [].
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),
[ end, generate ], vhdl_opt_identifier(ID).
vhdl_process_statement(vhdl_process(ID,Post,SL,DI,Ss)) -->
vhdl_opt_label(ID), 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_identifier(ID).
vhdl_opt_label(ID) --> vhdl_identifier(ID), [':'], !.
vhdl_opt_label(null) --> [].
vhdl_opt_label_use(ID) --> vhdl_identifier(ID), !.
vhdl_opt_label_use(null) --> [].
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.
When more than one semi-colon terminated statement is part of a production, we must call vhdl_get_more//0 to read more tokens.
vhdl_sequential_statements([S|Ss]) -->
vhdl_sequential_statement(S),
vhdl_get_more, !,
vhdl_sequential_statements(Ss).
vhdl_sequential_statements([]) --> [].
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_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) --> [].
vhdl_report_statement(report(LID,String,Severity)) -->
vhdl_opt_label(LID),
[report], !,
vhdl_expression(String),
vhdl_opt_severity(Severity).
vhdl_case_statement(case(LID,Cond,Cases)) -->
vhdl_opt_label(LID),
[ case ], vhdl_expression(Cond), [ is ], !,
vhdl_case_statement_alternatives(Cases),
[ end, case ], vhdl_opt_identifier(LID).
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([]) --> [].
vhdl_exit_statement(vhdl_exit(LID,ID,Expr)) -->
vhdl_opt_label(LID),
[ exit ], vhdl_opt_label_use(ID),
vhdl_opt_when_condition(Expr).
vhdl_opt_when_condition(Expr) -->
[ when ], !, vhdl_expression(Expr).
vhdl_opt_when_condition(null) --> [ ].
vhdl_if_statement(vhdl_if(LID,Cond,Thens,Elses)) -->
vhdl_opt_label(LID),
[ if ], vhdl_expression(Cond),
[ then ], vhdl_sequential_statements(Thens),
vhdl_else(LID,Elses).
vhdl_else(LID,elsif(ECond,Thens,Else)) -->
[ elsif ], !,
vhdl_expression(ECond),
[ then ],
vhdl_sequential_statements(Thens),
vhdl_else(LID,Else).
vhdl_else(LID,Elses) -->
[ else ], !, vhdl_sequential_statements(Elses),
vhdl_end(LID).
vhdl_else(LID,[]) --> vhdl_end(LID), !.
vhdl_end(LID) --> [ end, if ], vhdl_opt_identifier(LID).
vhdl_loop_statement(vhdl_loop(LID,IScheme,Ss)) -->
vhdl_opt_label(LID),
vhdl_opt_iteration_scheme(IScheme),
[ loop ],
vhdl_sequential_statements(Ss),
[ end, loop ], vhdl_opt_identifier(LID).
vhdl_next_statement(vhdl_next(LID,ID,Expr)) -->
vhdl_opt_label(LID),
[ next ], vhdl_opt_label_use(ID),
vhdl_opt_when_condition(Expr).
vhdl_null_statement(null(LID)) -->
vhdl_opt_label(LID), [null].
vhdl_procedure_call_statement(vhdl_call(LID,PID,Args)) -->
vhdl_opt_label(LID),
vhdl_name(PID), vhdl_opt_association_list(Args).
vhdl_return_statement(return(LID,Expr)) -->
vhdl_opt_label(LID),
[ return ], vhdl_expression(Expr).
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).
vhdl_variable_assignment_statement(assign(LID,Var,Expr)) -->
vhdl_opt_label(LID),
vhdl_target(Var), [ ':=' ], vhdl_expression(Expr).
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) --> [].
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).
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.
vhdl_block_specification(vhdl_name(ID,Index)) -->
vhdl_mark(ID),
( [ '(' ], !, vhdl_index_specification(Index), [ ')' ]
; { Index = null } ).
vhdl_index_specification(Range) --> vhdl_discrete_range(Range). vhdl_index_specification(Expr) --> vhdl_expression(Expr).
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).
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.
vhdl_configuration_specification(vhdl_spec(CSpec,BI)) -->
[ for ], vhdl_component_specification(CSpec),
vhdl_opt_binding_indication(BI).
vhdl_component_specification(spec(Spec,ID)) -->
vhdl_instantiation_list(Spec), [':'], vhdl_mark(ID).
vhdl_instantiation_list(all) --> [all], !. vhdl_instantiation_list(others) --> [others], !. vhdl_instantiation_list(IL) --> vhdl_identifier_list(IL).
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) --> [].
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) --> [].
We now highlight the revisions made to the original VHDL-87 parser to conform to the IEEE Standard 1076-1993 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 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.) The price we pay, is a small increase in time required for parsing.