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.
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 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) --> { 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([]) --> [].
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_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).
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,_,_,_).
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 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). % 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([]) --> [].
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_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_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).
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_constrained_nature_definition(vhdl_nature_array(IC,SI)) --> [array], vhdl_index_constraint(IC), [of], vhdl_subnature_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_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 ], ! ; []).
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_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).
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,TA))--> vhdl_opt_mark(FM), vhdl_mark(TM), vhdl_opt_constraint(C), vhdl_opt_tolerance_aspect(TA).
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].
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) --> [].
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.
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).
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_object_class(quantity) --> [quantity], !. vhdl_object_class(terminal) --> [terminal], !.
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_entity_class(nature) --> [ nature ], !. vhdl_entity_class(subnature) --> [ subnature ], !. vhdl_entity_class(quantity) --> [ quantity ], !. vhdl_entity_class(terminal) --> [ terminal ], !.
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). 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.
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([]) --> [].
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).
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.
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) --> [].
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_sequential_statement(S) --> vhdl_break_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,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).
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(LID,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,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).
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).
vhdl_next_statement(vhdl_next(LID,ID,Expr)) --> vhdl_opt_label(LID), [ next ], vhdl_opt_label_use(LID,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) --> [].
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) --> [].
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).
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).
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([]) --> [].
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).
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).
vhdl_simultaneous_null_statement(simultaneous_null(LID)) --> vhdl_opt_label(LID), [null].
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, 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.
On UNIX, the command
#!/bin/sh #SAVE-VERSION=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:#PROLOG-VERSION= exec ${SWIPL-/path-to-emulator} -x $0 "$@" ...
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.