%% vim: tabstop=8:shiftwidth=4 %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2000-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% -module(asn1ct_parser2). -export([parse/2,format_error/1]). -include("asn1_records.hrl"). %% Only used internally within this module. -record(typereference, {pos,val}). -record(constraint, {c,e}). -record(identifier, {pos,val}). parse(File0, Tokens0) -> try do_parse(Tokens0) of {ok,#module{}}=Result -> Result catch throw:{asn1_error,Fun} when is_function(Fun, 0) -> handle_parse_error(File0, Fun()); throw:{asn1_error,{parse_error,Tokens}} -> handle_parse_error(File0, Tokens) after clean_process_dictionary() end. handle_parse_error(File0, [Token|_]) -> File = filename:basename(File0), Line = get_line(Token), Error = {structured_error,{File,Line},?MODULE, {syntax_error,get_token(Token)}}, {error,[Error]}. do_parse(Tokens0) -> {ModuleDefinition,Tokens1} = parse_ModuleDefinition(Tokens0), {Types,Tokens2} = parse_AssignmentList(Tokens1), case Tokens2 of [{'END',_}|_Rest3] -> {ok,ModuleDefinition#module{typeorval=Types}}; _ -> parse_error(Tokens2) end. clean_process_dictionary() -> Mod = erase(asn1_module), _ = erase({Mod,imports}), _ = erase(tagdefault), _ = erase(extensiondefault), ok. format_error({syntax_error,Token}) when is_atom(Token) -> io_lib:format("syntax error before: '~s'", [Token]); format_error({syntax_error,Token}) -> io_lib:format("syntax error before: '~p'", [Token]). parse_ModuleDefinition([{typereference,L1,ModuleIdentifier}|Rest0]) -> put(asn1_module,ModuleIdentifier), {_DefinitiveIdentifier,Rest02} = case Rest0 of [{'{',_}|_Rest01] -> parse_ObjectIdentifierValue(Rest0); _ -> {[],Rest0} end, Rest = case Rest02 of [{'DEFINITIONS',_}|Rest03] -> Rest03; _ -> parse_error(Rest02) end, {TagDefault,Rest2} = case Rest of [{'EXPLICIT',_L3},{'TAGS',_L4}|Rest1] -> put(tagdefault,'EXPLICIT'), {'EXPLICIT',Rest1}; [{'IMPLICIT',_L3},{'TAGS',_L4}|Rest1] -> put(tagdefault,'IMPLICIT'), {'IMPLICIT',Rest1}; [{'AUTOMATIC',_L3},{'TAGS',_L4}|Rest1] -> put(tagdefault,'AUTOMATIC'), {'AUTOMATIC',Rest1}; Rest1 -> put(tagdefault,'EXPLICIT'), {'EXPLICIT',Rest1} % The default end, {ExtensionDefault,Rest3} = case Rest2 of [{'EXTENSIBILITY',_L5}, {'IMPLIED',_L6}|Rest21] -> put(extensiondefault,'IMPLIED'),{'IMPLIED',Rest21}; _ -> put(extensiondefault,undefined),{undefined,Rest2} end, case Rest3 of [{'::=',_L7}, {'BEGIN',_L8}|Rest4] -> {Exports, Rest5} = parse_Exports(Rest4), {{imports, Imports}, Rest6} = parse_Imports(Rest5), put({get(asn1_module), imports}, Imports), {#module{ pos = L1, name = ModuleIdentifier, defid = [], % fix this tagdefault = TagDefault, extensiondefault = ExtensionDefault, exports = Exports, imports = {imports, Imports}}, Rest6}; _ -> parse_error(Rest3) end; parse_ModuleDefinition(Tokens) -> parse_error(Tokens). parse_Exports([{'EXPORTS',_L1},{';',_L2}|Rest]) -> {{exports,[]},Rest}; parse_Exports([{'EXPORTS',_},{'ALL',_},{';',_}|Rest]) -> %% Same as no exports definition. {{exports,all},Rest}; parse_Exports([{'EXPORTS',_L1}|Rest]) -> {SymbolList,Rest2} = parse_SymbolList(Rest), case Rest2 of [{';',_}|Rest3] -> {{exports,SymbolList},Rest3}; _ -> parse_error(Rest2) end; parse_Exports(Rest) -> {{exports,all},Rest}. parse_SymbolList(Tokens) -> parse_SymbolList(Tokens,[]). parse_SymbolList(Tokens,Acc) -> {Symbol,Rest} = parse_Symbol(Tokens), case Rest of [{',',_L1}|Rest2] -> parse_SymbolList(Rest2,[Symbol|Acc]); Rest2 -> {lists:reverse(Acc, [Symbol]),Rest2} end. parse_Symbol(Tokens) -> parse_Reference(Tokens). parse_Reference([{typereference,L1,TrefName},{'{',_L2},{'}',_L3}|Rest]) -> {tref2Exttref(L1,TrefName),Rest}; parse_Reference([Tref1 = {typereference,_,_},{'.',_},Tref2 = {typereference,_,_}, {'{',_L2},{'}',_L3}|Rest]) -> {{tref2Exttref(Tref1),tref2Exttref(Tref2)},Rest}; parse_Reference([Tref = {typereference,_L1,_TrefName}|Rest]) -> {tref2Exttref(Tref),Rest}; parse_Reference([#identifier{}=Vref,{'{',_L2},{'}',_L3}|Rest]) -> {identifier2Extvalueref(Vref),Rest}; parse_Reference([#identifier{}=Vref|Rest]) -> {identifier2Extvalueref(Vref),Rest}; parse_Reference(Tokens) -> parse_error(Tokens). parse_Imports([{'IMPORTS',_L1},{';',_L2}|Rest]) -> {{imports,[]},Rest}; parse_Imports([{'IMPORTS',_L1}|Rest]) -> {SymbolsFromModuleList,Rest2} = parse_SymbolsFromModuleList(Rest), case Rest2 of [{';',_L2}|Rest3] -> {{imports,SymbolsFromModuleList},Rest3}; _ -> parse_error(Rest2) end; parse_Imports(Tokens) -> {{imports,[]},Tokens}. parse_SymbolsFromModuleList(Tokens) -> parse_SymbolsFromModuleList(Tokens,[]). parse_SymbolsFromModuleList(Tokens,Acc) -> {SymbolsFromModule,Rest} = parse_SymbolsFromModule(Tokens), try parse_SymbolsFromModule(Rest) of {Sl,_Rest2} when is_record(Sl,'SymbolsFromModule') -> parse_SymbolsFromModuleList(Rest, [SymbolsFromModule|Acc]) catch throw:{asn1_error,_} -> {lists:reverse(Acc, [SymbolsFromModule]),Rest} end. parse_SymbolsFromModule(Tokens) -> SetRefModuleName = fun(N) -> fun(X) when is_record(X,'Externaltypereference')-> X#'Externaltypereference'{module=N}; (X) when is_record(X,'Externalvaluereference')-> X#'Externalvaluereference'{module=N} end end, {SymbolList,Rest} = parse_SymbolList(Tokens), case Rest of [{'FROM',_L1},{typereference,_,Name}=Tref| [#identifier{},{',',_}|_]=Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name), SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest2}; %% This a special case when there is only one Symbol imported %% from the next module. No other way to distinguish Ref from %% a part of the GlobalModuleReference of Name. [{'FROM',_L1},{typereference,_,Name}=Tref| [#identifier{},{'FROM',_}|_]=Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name), SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest2}; [{'FROM',_L1},{typereference,_,Name}=Tref,#identifier{}|Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name), SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest2}; [{'FROM',_L1},{typereference,_,Name}=Tref|[{'{',_}|_]=Rest2] -> {_ObjIdVal,Rest3} = parse_ObjectIdentifierValue(Rest2), % value not used yet, fix me NewSymbolList = lists:map(SetRefModuleName(Name), SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest3}; [{'FROM',_L1},{typereference,_,Name}=Tref|Rest2] -> NewSymbolList = lists:map(SetRefModuleName(Name), SymbolList), {#'SymbolsFromModule'{symbols=NewSymbolList, module=tref2Exttref(Tref)},Rest2}; _ -> parse_error(Rest) end. parse_ObjectIdentifierValue([{'{',_}|Rest]) -> parse_ObjectIdentifierValue(Rest,[]). parse_ObjectIdentifierValue([{number,_,Num}|Rest], Acc) -> parse_ObjectIdentifierValue(Rest,[Num|Acc]); parse_ObjectIdentifierValue([#identifier{val=Id},{'(',_},{number,_,Num},{')',_}|Rest], Acc) -> parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,Num}|Acc]); parse_ObjectIdentifierValue([#identifier{val=Id},{'(',_},#identifier{val=Id2},{')',_}|Rest], Acc) -> parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,Id2}|Acc]); parse_ObjectIdentifierValue([#identifier{val=Id},{'(',_},{typereference,_,Tref},{'.',_},#identifier{val=Id2}, {')',_}|Rest], Acc) -> parse_ObjectIdentifierValue(Rest, [{'NamedNumber',Id,{'ExternalValue',Tref,Id2}}|Acc]); parse_ObjectIdentifierValue([#identifier{}=Id|Rest], Acc) -> parse_ObjectIdentifierValue(Rest, [identifier2Extvalueref(Id)|Acc]); parse_ObjectIdentifierValue([{'}',_}|Rest], Acc) -> {lists:reverse(Acc),Rest}; parse_ObjectIdentifierValue(Tokens, _Acc) -> parse_error(Tokens). parse_AssignmentList(Tokens) -> parse_AssignmentList(Tokens, []). parse_AssignmentList([{'END',_}|_]=Tokens, Acc) -> {lists:reverse(Acc),Tokens}; parse_AssignmentList([{'$end',_}|_]=Tokens, Acc) -> {lists:reverse(Acc),Tokens}; parse_AssignmentList(Tokens0, Acc) -> {Assignment,Tokens} = parse_Assignment(Tokens0), parse_AssignmentList(Tokens, [Assignment|Acc]). parse_Assignment([{typereference,L1,Name},{'::=',_}|Tokens0]) -> %% 1) Type ::= TypeDefinition %% 2) CLASS-NAME ::= CLASS {...} Flist = [{type,fun parse_Type/1}, {class,fun parse_ObjectClass/1}], case parse_or_tag(Tokens0, Flist) of {{type,Type},Tokens} -> %% TypeAssignment {#typedef{pos=L1,name=Name,typespec=Type},Tokens}; {{class,Type},Tokens} -> %% ObjectClassAssignment {#classdef{pos=L1,name=Name,module=resolve_module(Type), typespec=Type},Tokens} end; parse_Assignment([{typereference,_,_},{'{',_}|_]=Tokens) -> %% 1) Type{...} ::= ... %% 2) ValueSet{...} Type ::= ... %% ObjectSet{...} CLASS-NAME ::= CLASS {...} %% 3) CLASS-NAME{...} ::= CLASS {...} %% A parameterized value set and and a parameterized object set %% cannot be distinguished from each other without type information. Flist = [fun parse_ParameterizedTypeAssignment/1, fun parse_ParameterizedValueSetTypeAssignment/1, fun parse_ParameterizedObjectClassAssignment/1], parse_or(Tokens, Flist); parse_Assignment([{typereference,_,_}|_]=Tokens) -> %% 1) ObjectSet CLASS-NAME ::= ... %% 2) ValueSet Type ::= ... Flist = [fun parse_ObjectSetAssignment/1, fun parse_ValueSetTypeAssignment/1], parse_or(Tokens, Flist); parse_Assignment([#identifier{},{'{',_}|_]=Tokens) -> %% 1) value{...} Type ::= ... %% 2) object{...} CLASS-NAME ::= ... Flist = [fun parse_ParameterizedValueAssignment/1, fun parse_ParameterizedObjectAssignment/1], parse_or(Tokens, Flist); parse_Assignment([#identifier{}|_]=Tokens) -> %% 1) value Type ::= ... %% 2) object CLASS-NAME ::= ... Flist = [fun parse_ValueAssignment/1, fun parse_ObjectAssignment/1], parse_or(Tokens, Flist); parse_Assignment(Tokens) -> parse_error(Tokens). parse_or(Tokens,Flist) -> parse_or(Tokens,Flist,[]). parse_or(Tokens, [Fun|Funs], ErrList) when is_function(Fun, 1) -> try Fun(Tokens) of {_,Rest}=Result when is_list(Rest) -> Result catch throw:{asn1_error,Error} -> parse_or(Tokens, Funs, [Error|ErrList]) end; parse_or(_Tokens, [], ErrList) -> throw({asn1_error,fun() -> prioritize_error(ErrList) end}). parse_or_tag(Tokens, Flist) -> parse_or_tag(Tokens, Flist, []). parse_or_tag(Tokens, [{Tag,Fun}|Funs], ErrList) when is_function(Fun, 1) -> try Fun(Tokens) of {Parsed,Rest} when is_list(Rest) -> {{Tag,Parsed},Rest} catch throw:{asn1_error,Error} -> parse_or_tag(Tokens, Funs, [Error|ErrList]) end; parse_or_tag(_Tokens, [], ErrList) -> throw({asn1_error,fun() -> prioritize_error(ErrList) end}). prioritize_error(Errors0) -> Errors1 = prioritize_error_1(Errors0), Errors2 = [{length(L),L} || L <- Errors1], Errors = lists:sort(Errors2), [Res|_] = [L || {_,L} <- Errors], Res. prioritize_error_1([F|T]) when is_function(F, 0) -> [F()|prioritize_error_1(T)]; prioritize_error_1([{parse_error,Tokens}|T]) -> [Tokens|prioritize_error_1(T)]; prioritize_error_1([]) -> []. %% parse_Type(Tokens) -> Ret %% %% Tokens = [Tok] %% Tok = tuple() %% Ret = #type{} %% parse_Type(Tokens) -> {Tag,Rest3} = case Tokens of [{'[',_}|_] -> parse_Tag(Tokens); _ -> {[],Tokens} end, {Tag2,Rest4} = case Rest3 of [{'IMPLICIT',_}|Rest31] when is_record(Tag,tag)-> {[Tag#tag{type='IMPLICIT'}],Rest31}; [{'EXPLICIT',_}|Rest31] when is_record(Tag,tag)-> {[Tag#tag{type='EXPLICIT'}],Rest31}; Rest31 when is_record(Tag,tag) -> {[Tag#tag{type={default,get(tagdefault)}}],Rest31}; Rest31 -> {Tag,Rest31} end, Flist = [fun parse_BuiltinType/1, fun parse_ReferencedType/1, fun parse_TypeWithConstraint/1], {Type,Rest5} = parse_or(Rest4, Flist), case Rest5 of [{'(',_}|_] -> {Constraints,Rest6} = parse_Constraints(Rest5), {Type#type{tag=Tag2, constraint=merge_constraints(Constraints)},Rest6}; [_|_] -> {Type#type{tag=Tag2},Rest5} end. parse_BuiltinType([{'BIT',_},{'STRING',_}|Rest]) -> case Rest of [{'{',_}|Rest2] -> {NamedNumberList,Rest3} = parse_NamedNumberList(Rest2), case Rest3 of [{'}',_}|Rest4] -> {#type{def={'BIT STRING',NamedNumberList}},Rest4}; _ -> parse_error(Rest3) end; _ -> {#type{def={'BIT STRING',[]}},Rest} end; parse_BuiltinType([{'BOOLEAN',_}|Rest]) -> {#type{def='BOOLEAN'},Rest}; %% CharacterStringType ::= RestrictedCharacterStringType | %% UnrestrictedCharacterStringType parse_BuiltinType([{restrictedcharacterstringtype,_,StringName}|Rest]) -> {#type{def=StringName},Rest}; parse_BuiltinType([{'CHARACTER',_},{'STRING',_}|Rest]) -> {#type{def='CHARACTER STRING'},Rest}; parse_BuiltinType([{'CHOICE',_},{'{',_}|Rest]) -> {L0,Rest2} = parse_AlternativeTypeLists(Rest), case Rest2 of [{'}',_}|Rest3] -> NeedExt = not lists:keymember('EXTENSIONMARK', 1, L0) andalso get(extensiondefault) =:= 'IMPLIED', L = case NeedExt of true -> L0 ++ [#'EXTENSIONMARK'{}]; false -> L0 end, {#type{def={'CHOICE',L}},Rest3}; _ -> parse_error(Rest2) end; parse_BuiltinType([{'EMBEDDED',_},{'PDV',_}|Rest]) -> {#type{def='EMBEDDED PDV'},Rest}; parse_BuiltinType([{'ENUMERATED',_},{'{',_}|Rest]) -> {Enumerations,Rest2} = parse_Enumerations(Rest), case Rest2 of [{'}',_}|Rest3] -> {#type{def={'ENUMERATED',Enumerations}},Rest3}; _ -> parse_error(Rest2) end; parse_BuiltinType([{'EXTERNAL',_}|Rest]) -> {#type{def='EXTERNAL'},Rest}; parse_BuiltinType([{'INSTANCE',_},{'OF',_}|Rest]) -> {DefinedObjectClass,Rest2} = parse_DefinedObjectClass(Rest), case Rest2 of [{'(',_}|_] -> {Constraint0,Rest3} = parse_Constraint(Rest2), Constraint = merge_constraints([Constraint0]), {#type{def={'INSTANCE OF',DefinedObjectClass,Constraint}},Rest3}; _ -> {#type{def={'INSTANCE OF',DefinedObjectClass,[]}},Rest2} end; parse_BuiltinType([{'INTEGER',_}|Rest]) -> case Rest of [{'{',_}|Rest2] -> {NamedNumberList,Rest3} = parse_NamedNumberList(Rest2), case Rest3 of [{'}',_}|Rest4] -> {#type{def={'INTEGER',NamedNumberList}},Rest4}; _ -> parse_error(Rest3) end; _ -> {#type{def='INTEGER'},Rest} end; parse_BuiltinType([{'NULL',_}|Rest]) -> {#type{def='NULL'},Rest}; parse_BuiltinType([{'OBJECT',_},{'IDENTIFIER',_}|Rest]) -> {#type{def='OBJECT IDENTIFIER'},Rest}; parse_BuiltinType([{'OCTET',_},{'STRING',_}|Rest]) -> {#type{def='OCTET STRING'},Rest}; parse_BuiltinType([{'REAL',_}|Rest]) -> {#type{def='REAL'},Rest}; parse_BuiltinType([{'RELATIVE-OID',_}|Rest]) -> {#type{def='RELATIVE-OID'},Rest}; parse_BuiltinType([{'SEQUENCE',_},{'{',_},{'}',_}|Rest]) -> {#type{def=#'SEQUENCE'{components=[]}}, Rest}; parse_BuiltinType([{'SEQUENCE',_},{'{',_},{'...',Line},{'}',_}|Rest]) -> {#type{def=#'SEQUENCE'{components=[#'EXTENSIONMARK'{pos = Line}]}},Rest}; parse_BuiltinType([{'SEQUENCE',_},{'{',_},{'...',Line},{'!',_}|Rest]) -> {ExceptionIdentification,Rest2} = parse_ExceptionIdentification(Rest), case Rest2 of [{'}',_}|Rest3] -> {#type{def=#'SEQUENCE'{ components=[#'EXTENSIONMARK'{ pos = Line, val = ExceptionIdentification}]}}, Rest3}; _ -> {ComponentTypeLists,Rest3}= parse_ComponentTypeLists2(Rest2,[#'EXTENSIONMARK'{pos=Line}]), case Rest3 of [{'}',_}|Rest4] -> {#type{def=#'SEQUENCE'{components=ComponentTypeLists}},Rest4}; _ -> parse_error(Rest3) end end; parse_BuiltinType([{'SEQUENCE',_},{'{',_}|Rest]) -> {ComponentTypeLists,Rest2} = parse_ComponentTypeLists(Rest), case Rest2 of [{'}',_}|Rest3] -> ComponentTypeLists2 = case {[Ext||Ext = #'EXTENSIONMARK'{} <- ComponentTypeLists], get(extensiondefault)} of {[],'IMPLIED'} -> ComponentTypeLists ++ [#'EXTENSIONMARK'{}]; _ -> ComponentTypeLists end, {#type{def=#'SEQUENCE'{components = ComponentTypeLists2}}, Rest3}; _ -> parse_error(Rest2) end; parse_BuiltinType([{'SEQUENCE',_},{'OF',_}| [#identifier{},{'<',_}|_]=Tokens0]) -> {Type,Tokens} = parse_SelectionType(Tokens0), {#type{def={'SEQUENCE OF',Type}},Tokens}; parse_BuiltinType([{'SEQUENCE',_},{'OF',_},#identifier{} |Rest]) -> %% TODO: take care of the identifier for something useful {Type,Rest2} = parse_Type(Rest), {#type{def={'SEQUENCE OF',Type}},Rest2}; parse_BuiltinType([{'SEQUENCE',_},{'OF',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#type{def={'SEQUENCE OF',Type}},Rest2}; parse_BuiltinType([{'SET',_},{'{',_},{'...',Line},{'}',_}|Rest]) -> {#type{def=#'SET'{components=[#'EXTENSIONMARK'{pos = Line}]}},Rest}; parse_BuiltinType([{'SET',_},{'{',_},{'...',Line},{'!',_}|Rest]) -> {ExceptionIdentification,Rest2} = parse_ExceptionIdentification(Rest), case Rest2 of [{'}',_}|Rest3] -> {#type{def=#'SET'{components= [#'EXTENSIONMARK'{pos = Line, val = ExceptionIdentification}]}}, Rest3}; _ -> {ComponentTypeLists,Rest3}= parse_ComponentTypeLists2(Rest2,[#'EXTENSIONMARK'{pos=Line}]), case Rest3 of [{'}',_}|Rest4] -> {#type{def=#'SET'{components=ComponentTypeLists}},Rest4}; _ -> parse_error(Rest3) end end; parse_BuiltinType([{'SET',_},{'{',_}|Rest]) -> {ComponentTypeLists,Rest2} = parse_ComponentTypeLists(Rest), case Rest2 of [{'}',_}|Rest3] -> ComponentTypeLists2 = case {[Ext||Ext = #'EXTENSIONMARK'{} <- ComponentTypeLists], get(extensiondefault)} of {[],'IMPLIED'} -> ComponentTypeLists ++ [#'EXTENSIONMARK'{}]; _ -> ComponentTypeLists end, {#type{def=#'SET'{components = ComponentTypeLists2}}, Rest3}; _ -> parse_error(Rest2) end; parse_BuiltinType([{'SET',_},{'OF',_}| [#identifier{},{'<',_}|_]=Tokens0]) -> {Type,Tokens} = parse_SelectionType(Tokens0), {#type{def={'SET OF',Type}},Tokens}; parse_BuiltinType([{'SET',_},{'OF',_},#identifier{}|Rest]) -> %%TODO: take care of the identifier for something useful {Type,Rest2} = parse_Type(Rest), {#type{def={'SET OF',Type}},Rest2}; parse_BuiltinType([{'SET',_},{'OF',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#type{def={'SET OF',Type}},Rest2}; parse_BuiltinType([{'GeneralizedTime',_}|Rest]) -> {#type{def='GeneralizedTime'},Rest}; parse_BuiltinType([{'UTCTime',_}|Rest]) -> {#type{def='UTCTime'},Rest}; parse_BuiltinType([{'ObjectDescriptor',_}|Rest]) -> {#type{def='ObjectDescriptor'},Rest}; parse_BuiltinType([{'ANY',_},{'DEFINED',_},{'BY',_},#identifier{val=Id}|Rest]) -> %% For compatibility with the old standard. {#type{def={'ANY_DEFINED_BY',Id}},Rest}; parse_BuiltinType([{'ANY',_}|Rest]) -> %% For compatibility with the old standard. {#type{def='ANY'},Rest}; parse_BuiltinType(Tokens) -> parse_ObjectClassFieldType(Tokens). parse_TypeWithConstraint([{'SEQUENCE',_}|[{'(',_}|_]=Rest0]) -> {Constraint,Rest2} = parse_Constraint(Rest0), Rest4 = case Rest2 of [{'OF',_},#identifier{}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> parse_error(Rest2) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SEQUENCE OF',Type}, constraint = merge_constraints([Constraint])},Rest5}; parse_TypeWithConstraint([{'SEQUENCE',_},{'SIZE',_}|[{'(',_}|_]=Rest0]) -> {Constraint,Rest2} = parse_Constraint(Rest0), #constraint{c=C} = Constraint, Constraint2 = Constraint#constraint{c={element_set,{'SizeConstraint',C}, none}}, Rest4 = case Rest2 of [{'OF',_},#identifier{}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> parse_error(Rest2) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SEQUENCE OF',Type}, constraint = merge_constraints([Constraint2])},Rest5}; parse_TypeWithConstraint([{'SET',_}|[{'(',_}|_]=Rest0]) -> {Constraint,Rest2} = parse_Constraint(Rest0), Rest4 = case Rest2 of [{'OF',_},#identifier{}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> parse_error(Rest2) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SET OF',Type}, constraint = merge_constraints([Constraint])},Rest5}; parse_TypeWithConstraint([{'SET',_},{'SIZE',_}|[{'(',_}|_]=Rest0]) -> {Constraint,Rest2} = parse_Constraint(Rest0), #constraint{c=C} = Constraint, Constraint2 = Constraint#constraint{c={element_set, {'SizeConstraint',C},none}}, Rest4 = case Rest2 of [{'OF',_},#identifier{}|Rest3] -> %%% TODO: make some use of the identifier, maybe useful in the XML mapping Rest3; [{'OF',_}|Rest3] -> Rest3; _ -> parse_error(Rest2) end, {Type,Rest5} = parse_Type(Rest4), {#type{def = {'SET OF',Type}, constraint = merge_constraints([Constraint2])},Rest5}; parse_TypeWithConstraint(Tokens) -> parse_error(Tokens). %% -------------------------- parse_ReferencedType(Tokens) -> Flist = [fun parse_ParameterizedType/1, fun parse_DefinedType/1, fun parse_SelectionType/1, fun parse_TypeFromObject/1], parse_or(Tokens, Flist). parse_DefinedType([{typereference,L1,Module}, {'.',_}, {typereference,_,TypeName}|Tokens]) -> {#type{def = #'Externaltypereference'{pos=L1,module=Module, type=TypeName}},Tokens}; parse_DefinedType([{typereference,_,_}=Tr|Tokens]) -> {#type{def=tref2Exttref(Tr)},Tokens}; parse_DefinedType(Tokens) -> parse_error(Tokens). parse_SelectionType([#identifier{val=Name},{'<',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#type{def={'SelectionType',Name,Type}},Rest2}; parse_SelectionType(Tokens) -> parse_error(Tokens). resolve_module(Type) -> Current = get(asn1_module), Imports = get({Current, imports}), resolve_module(Type, Current, Imports). resolve_module(_Type, Current, undefined) -> Current; resolve_module(Type, Current, Imports) -> case [Mod || #'SymbolsFromModule'{symbols = S, module = Mod} <- Imports, #'Externaltypereference'{type = T} <- S, Type =:= T] of [#'Externaltypereference'{type = Mod}|_] -> Mod; %% This allows the same symbol to be imported several times %% which ought to be checked elsewhere and flagged as an error [] -> Current end. parse_Constraints(Tokens) -> parse_Constraints(Tokens,[]). parse_Constraints(Tokens,Acc) -> {Constraint,Rest} = parse_Constraint(Tokens), case Rest of [{'(',_}|_Rest2] -> parse_Constraints(Rest, [Constraint|Acc]); _ -> {lists:reverse(Acc, [Constraint]),Rest} end. parse_Constraint([{'(',_}|Rest]) -> {Constraint,Rest2} = parse_ConstraintSpec(Rest), {Exception,Rest3} = parse_ExceptionSpec(Rest2), case Rest3 of [{')',_}|Rest4] -> {#constraint{c=Constraint,e=Exception},Rest4}; [_|_] -> parse_error(Rest3) end. parse_ConstraintSpec(Tokens) -> Flist = [fun parse_GeneralConstraint/1, fun parse_SubtypeConstraint/1], parse_or(Tokens, Flist). parse_ExceptionSpec([LPar={')',_}|Rest]) -> {undefined,[LPar|Rest]}; parse_ExceptionSpec([{'!',_}|Rest]) -> parse_ExceptionIdentification(Rest); parse_ExceptionSpec(Tokens) -> parse_error(Tokens). parse_ExceptionIdentification(Tokens) -> Flist = [fun parse_SignedNumber/1, fun parse_DefinedValue/1, fun parse_TypeColonValue/1], parse_or(Tokens, Flist). parse_TypeColonValue(Tokens) -> {Type,Rest} = parse_Type(Tokens), case Rest of [{':',_}|Rest2] -> {Value,Rest3} = parse_Value(Rest2), {{Type,Value},Rest3}; [_|_] -> parse_error(Rest) end. parse_SubtypeConstraint(Tokens) -> parse_ElementSetSpecs(Tokens). parse_ElementSetSpecs(Tokens) -> {RootElems,Rest} = parse_ElementSetSpec(Tokens), case Rest of [{',',_},{'...',_},{',',_}|Rest2] -> {AdditionalElems,Rest3} = parse_ElementSetSpec(Rest2), {{element_set,RootElems,AdditionalElems},Rest3}; [{',',_},{'...',_}|Rest2] -> {{element_set,RootElems,empty},Rest2}; _ -> {{element_set,RootElems,none},Rest} end. parse_ElementSetSpec([{'ALL',_},{'EXCEPT',_}|Rest]) -> {Exclusions,Rest2} = parse_Elements(Rest), {{'ALL-EXCEPT',Exclusions},Rest2}; parse_ElementSetSpec(Tokens) -> parse_Unions(Tokens). %% parse_Unions(Tokens) -> {Ret,Rest} %% Tokens = [Tok] %% Tok = tuple() %% Ret = {'SingleValue',list()} | list() | %% parse_Unions(Tokens) -> {InterSec,Rest} = parse_Intersections(Tokens), {Unions,Rest2} = parse_UnionsRec(Rest), case {InterSec,Unions} of {InterSec,[]} -> {InterSec,Rest2}; {V1,V2} -> {{union,V1,V2},Rest2} end. parse_UnionsRec([{'|',_}|Rest]) -> {InterSec,Rest2} = parse_Intersections(Rest), {URec,Rest3} = parse_UnionsRec(Rest2), case {InterSec,URec} of {V1,[]} -> {V1,Rest3}; {V1,V2} -> {{union,V1,V2},Rest3} end; parse_UnionsRec([{'UNION',Info}|Rest]) -> parse_UnionsRec([{'|',Info}|Rest]); parse_UnionsRec(Tokens) -> {[],Tokens}. parse_Intersections(Tokens) -> {InterSec,Rest} = parse_IntersectionElements(Tokens), {IRec,Rest2} = parse_IElemsRec(Rest), case {InterSec,IRec} of {V1,[]} -> {V1,Rest2}; {V1,V2} -> {{intersection,V1,V2},Rest2} end. %% parse_IElemsRec(Tokens) -> Result %% Result ::= {'SingleValue',ordered_set()} | list() parse_IElemsRec([{'^',_}|Rest]) -> {InterSec,Rest2} = parse_IntersectionElements(Rest), {IRec,Rest3} = parse_IElemsRec(Rest2), case {InterSec,IRec} of {V1,[]} -> {V1,Rest2}; {V1,V2} -> {{intersection,V1,V2},Rest3} end; parse_IElemsRec([{'INTERSECTION',Info}|Rest]) -> parse_IElemsRec([{'^',Info}|Rest]); parse_IElemsRec(Tokens) -> {[],Tokens}. %% parse_IntersectionElements(Tokens) -> {Result,Rest} %% Result ::= InterSec | {InterSec,{'EXCEPT',Exclusion}} %% InterSec ::= {'ALL',{'EXCEPT',Exclusions}} | Unions %% Unions ::= {'SingleValue',list()} | list() (see parse_Unions) %% Exclusions ::= InterSec parse_IntersectionElements(Tokens) -> {InterSec,Rest} = parse_Elements(Tokens), case Rest of [{'EXCEPT',_}|Rest2] -> {Exclusion,Rest3} = parse_Elements(Rest2), {{'EXCEPT',InterSec,Exclusion},Rest3}; Rest -> {InterSec,Rest} end. %% parse_Elements(Tokens) -> {Result,Rest} %% Result ::= {'ALL',{'EXCEPT',Exclusions}} | Unions %% Exclusions ::= {'ALL',{'EXCEPT',Exclusions}} | Unions %% Unions ::= {'SingleValue',list()} | list() (see parse_Unions) parse_Elements([{'(',_}|Rest]) -> {Elems,Rest2} = parse_ElementSetSpec(Rest), case Rest2 of [{')',_}|Rest3] -> {Elems,Rest3}; [_|_] -> parse_error(Rest2) end; parse_Elements(Tokens) -> Flist = [fun parse_ObjectSetElements/1, fun parse_SubtypeElements/1, fun parse_Object/1, fun parse_DefinedObjectSet/1], parse_or(Tokens, Flist). %% -------------------------- parse_DefinedObjectClass([{typereference,_,ModName},{'.',_}, {typereference,Pos,Name}|Tokens]) -> Ext = #'Externaltypereference'{pos=Pos, module=ModName, type=Name}, {Ext,Tokens}; parse_DefinedObjectClass([Tr={typereference,_,_ObjClName}|Rest]) -> {tref2Exttref(Tr),Rest}; parse_DefinedObjectClass(Tokens) -> parse_error(Tokens). parse_ObjectClass(Tokens) -> Flist = [fun parse_ObjectClassDefn/1, fun parse_DefinedObjectClass/1], parse_or(Tokens, Flist). parse_ObjectClassDefn([{'CLASS',_},{'{',_}|Rest]) -> {Type,Rest2} = parse_FieldSpec(Rest), {WithSyntaxSpec,Rest3} = parse_WithSyntaxSpec(Rest2), {#objectclass{fields=Type,syntax=WithSyntaxSpec},Rest3}; parse_ObjectClassDefn(Tokens) -> parse_error(Tokens). parse_FieldSpec(Tokens) -> parse_FieldSpec(Tokens,[]). parse_FieldSpec(Tokens0, Acc) -> Fl = case Tokens0 of [{valuefieldreference,_,_}|_] -> %% 1) &field Type %% &object CLASS-NAME %% 2) &field &FieldName %% A fixed type field cannot be distinguished from %% an object field without type information. [fun parse_FixedTypeValueFieldSpec/1, fun parse_VariableTypeValueFieldSpec/1]; [{typefieldreference,_,_}|_] -> %% 1) &Set Type %% &ObjectSet CLASS-NAME %% 2) &Set &FieldName %% 3) &Type %% A value set and an object cannot be distinguished %% without type information. [fun parse_FixedTypeValueSetFieldSpec/1, fun parse_VariableTypeValueSetFieldSpec/1, fun parse_TypeFieldSpec/1]; [_|_] -> parse_error(Tokens0) end, case parse_or(Tokens0, Fl) of {Type,[{'}',_}|Rest]} -> {lists:reverse(Acc, [Type]),Rest}; {Type,[{',',_}|Rest2]} -> parse_FieldSpec(Rest2, [Type|Acc]) end. parse_PrimitiveFieldName([{typefieldreference,_,FieldName}|Rest]) -> {{typefieldreference,FieldName},Rest}; parse_PrimitiveFieldName([{valuefieldreference,_,FieldName}|Rest]) -> {{valuefieldreference,FieldName},Rest}; parse_PrimitiveFieldName(Tokens) -> parse_error(Tokens). parse_FieldName(Tokens) -> {Field,Rest} = parse_PrimitiveFieldName(Tokens), parse_FieldName(Rest,[Field]). parse_FieldName([{'.',_}|Rest0],Acc) -> {FieldName,Rest1} = parse_PrimitiveFieldName(Rest0), parse_FieldName(Rest1, [FieldName|Acc]); parse_FieldName(Tokens, Acc) -> {lists:reverse(Acc),Tokens}. parse_FixedTypeValueFieldSpec([{valuefieldreference,_,VFieldName}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {Unique,Rest3} = case Rest2 of [{'UNIQUE',_}|Rest4] -> {'UNIQUE',Rest4}; _ -> {undefined,Rest2} end, {OptionalitySpec,Rest5} = parse_ValueOptionalitySpec(Rest3), case is_end_delimiter(Rest5) of false -> parse_error(Rest5); true -> ok end, Tag = case Unique of 'UNIQUE' -> fixedtypevaluefield; _ -> object_or_fixedtypevalue_field end, {{Tag,VFieldName,Type,Unique,OptionalitySpec},Rest5}. parse_VariableTypeValueFieldSpec([{valuefieldreference,_,VFieldName}|Rest0]) -> {FieldRef,Rest1} = parse_FieldName(Rest0), {OptionalitySpec,Rest} = parse_ValueOptionalitySpec(Rest1), case is_end_delimiter(Rest) of true -> {{variabletypevaluefield,VFieldName,FieldRef,OptionalitySpec}, Rest}; false -> parse_error(Rest) end. parse_TypeFieldSpec([{typefieldreference,_,Name}|Rest0]) -> {OptionalitySpec,Rest} = parse_TypeOptionalitySpec(Rest0), case is_end_delimiter(Rest) of true -> {{typefield,Name,OptionalitySpec},Rest}; false -> parse_error(Rest) end. parse_FixedTypeValueSetFieldSpec([{typefieldreference,_,Name}|Rest0]) -> {Type,Rest1} = parse_Type(Rest0), {OptionalitySpec,Rest} = parse_ValueSetOptionalitySpec(Rest1), case is_end_delimiter(Rest) of true -> {{objectset_or_fixedtypevalueset_field,Name,Type, OptionalitySpec},Rest}; false -> parse_error(Rest) end. parse_VariableTypeValueSetFieldSpec([{typefieldreference,_,Name}|Rest0]) -> {FieldRef,Rest1} = parse_FieldName(Rest0), {OptionalitySpec,Rest} = parse_ValueSetOptionalitySpec(Rest1), case is_end_delimiter(Rest) of true -> {{variabletypevaluesetfield,Name,FieldRef,OptionalitySpec}, Rest}; false -> parse_error(Rest) end. is_end_delimiter([{',',_}|_]) -> true; is_end_delimiter([{'}',_}|_]) -> true; is_end_delimiter([_|_]) -> false. parse_ValueOptionalitySpec(Tokens)-> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {Value,Rest2} = parse_Value(Rest), {{'DEFAULT',Value},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_TypeOptionalitySpec(Tokens) -> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {Type,Rest2} = parse_Type(Rest), {{'DEFAULT',Type},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_ValueSetOptionalitySpec(Tokens) -> case Tokens of [{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest}; [{'DEFAULT',_}|Rest] -> {ValueSet,Rest2} = parse_ValueSet(Rest), {{'DEFAULT',ValueSet},Rest2}; _ -> {'MANDATORY',Tokens} end. parse_WithSyntaxSpec([{'WITH',_},{'SYNTAX',_}|Rest]) -> {SyntaxList,Rest2} = parse_SyntaxList(Rest), {{'WITH SYNTAX',SyntaxList},Rest2}; parse_WithSyntaxSpec(Tokens) -> {[],Tokens}. parse_SyntaxList([{'{',_}|Rest]) -> parse_SyntaxList(Rest,[]); parse_SyntaxList(Tokens) -> parse_error(Tokens). parse_SyntaxList(Tokens, Acc) -> {SyntaxList,Rest} = parse_TokenOrGroupSpec(Tokens), case Rest of [{'}',_}|Rest2] -> {lists:reverse(Acc, [SyntaxList]),Rest2}; _ -> parse_SyntaxList(Rest, [SyntaxList|Acc]) end. parse_TokenOrGroupSpec(Tokens) -> Flist = [fun parse_RequiredToken/1, fun parse_OptionalGroup/1], parse_or(Tokens, Flist). parse_RequiredToken([{typereference,_,WordName}|Rest]=Tokens) -> case is_word(WordName) of false -> parse_error(Tokens); true -> {WordName,Rest} end; parse_RequiredToken([{',',L1}|Rest]) -> {{',',L1},Rest}; parse_RequiredToken([{WordName,_}|Rest]=Tokens) -> case is_word(WordName) of false -> parse_error(Tokens); true -> {WordName,Rest} end; parse_RequiredToken(Tokens) -> parse_PrimitiveFieldName(Tokens). parse_OptionalGroup([{'[',_}|Rest]) -> {Spec,Rest2} = parse_TokenOrGroupSpec(Rest), {SpecList,Rest3} = parse_OptionalGroup(Rest2,[Spec]), {SpecList,Rest3}; parse_OptionalGroup(Tokens) -> parse_error(Tokens). parse_OptionalGroup([{']',_}|Rest],Acc) -> {lists:reverse(Acc),Rest}; parse_OptionalGroup(Tokens,Acc) -> {Spec,Rest} = parse_TokenOrGroupSpec(Tokens), parse_OptionalGroup(Rest,[Spec|Acc]). parse_DefinedObject([#identifier{}=Id|Rest]) -> {{object,identifier2Extvalueref(Id)},Rest}; parse_DefinedObject([{typereference,L1,ModName},{'.',_},#identifier{val=ObjName}|Rest]) -> {{object, #'Externaltypereference'{pos=L1,module=ModName,type=ObjName}},Rest}; parse_DefinedObject(Tokens) -> parse_error(Tokens). parse_ObjectAssignment([#identifier{pos=L1,val=ObjName}|Rest]) -> {Class,Rest2} = parse_DefinedObjectClass(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Object,Rest4} = parse_Object(Rest3), {#typedef{pos=L1,name=ObjName, typespec=#'Object'{classname=Class,def=Object}},Rest4}; _ -> parse_error(Rest2) end. %% parse_Object(Tokens) -> Ret %% Tokens = [Tok] %% Tok = tuple() %% Ret = {object,_} | {object, _, _} parse_Object(Tokens) -> %% The ObjectFromObject production is not included here, %% since it will have been catched by the ValueFromObject %% before we reach this point. Flist = [fun parse_ObjectDefn/1, fun parse_DefinedObject/1], parse_or(Tokens, Flist). parse_ObjectDefn(Tokens) -> Flist=[fun parse_DefaultSyntax/1, fun parse_DefinedSyntax/1], parse_or(Tokens, Flist). parse_DefaultSyntax([{'{',_}|Rest]) -> parse_DefaultSyntax(Rest,[]); parse_DefaultSyntax(Tokens) -> parse_error(Tokens). parse_DefaultSyntax(Tokens, Acc) -> {Setting,Rest} = parse_FieldSetting(Tokens), case Rest of [{',',_}|Rest2] -> parse_DefaultSyntax(Rest2,[Setting|Acc]); [{'}',_}|Rest3] -> {{object,defaultsyntax,lists:reverse(Acc, [Setting])},Rest3}; _ -> parse_error(Rest) end. parse_FieldSetting(Tokens) -> {{_,PrimFieldName},Rest} = parse_PrimitiveFieldName(Tokens), {Setting,Rest2} = parse_Setting(Rest), {{PrimFieldName,Setting},Rest2}. parse_DefinedSyntax([{'{',_}|Rest]) -> parse_DefinedSyntax(Rest, []); parse_DefinedSyntax(Tokens) -> parse_error(Tokens). parse_DefinedSyntax(Tokens,Acc) -> case Tokens of [{'}',_}|Rest2] -> {{object,definedsyntax,lists:reverse(Acc)},Rest2}; _ -> {DefSynTok,Rest3} = parse_DefinedSyntaxToken(Tokens), parse_DefinedSyntax(Rest3,[DefSynTok|Acc]) end. %% DefinedSyntaxToken ::= Literal | Setting %% Literal ::= word | ',' %% Setting ::= Type | Value | ValueSet | Object | ObjectSet %% word equals typereference, but no lower cases parse_DefinedSyntaxToken([{',',_}=Comma|Rest]) -> {Comma,Rest}; %% ObjectClassFieldType or a defined type with a constraint. %% Should also be able to parse a parameterized type. It may be %% impossible to distinguish between a parameterized type and a Literal %% followed by an object set. parse_DefinedSyntaxToken([{typereference,_,_Name},{T,_}|_]=Tokens) when T =:= '.'; T =:= '(' -> parse_Setting(Tokens); parse_DefinedSyntaxToken([{typereference,L1,Name}=TRef|Rest]=Tokens) -> case is_word(Name) of false -> case lookahead_definedsyntax(Rest) of word_or_setting -> {{setting,L1,tref2Exttref(TRef)},Rest}; setting -> parse_Setting(Tokens) end; true -> {{word_or_setting,L1,tref2Exttref(TRef)},Rest} end; parse_DefinedSyntaxToken(Tokens) -> try parse_Setting(Tokens) of {_,_}=Result -> Result catch throw:{asn1_error,_} -> parse_Word(Tokens) end. lookahead_definedsyntax([{typereference,_,Name}|_Rest]) -> case is_word(Name) of true -> word_or_setting; false -> setting end; lookahead_definedsyntax([{'}',_}|_Rest]) -> word_or_setting; lookahead_definedsyntax(_) -> setting. parse_Word([{Name,Pos}|Rest]=Tokens) -> case is_word(Name) of false -> parse_error(Tokens); true -> {{word_or_setting,Pos,tref2Exttref(Pos,Name)},Rest} end; parse_Word(Tokens) -> parse_error(Tokens). parse_Setting(Tokens) -> Flist = [{type_tag,fun parse_Type/1}, {value_tag,fun parse_Value/1}, {object_tag,fun parse_Object/1}, {objectset_tag,fun parse_ObjectSet/1}], case parse_or_tag(Tokens, Flist) of {{value_tag,_},_}=Result -> %% Keep the value_tag. Result; {{Tag,Setting},Rest} when is_atom(Tag) -> %% Remove all other tags. {Setting,Rest} end. parse_DefinedObjectSet([{typereference,L1,ModuleName},{'.',_}, {typereference,L2,ObjSetName}|Rest]) -> {{objectset,L1,#'Externaltypereference'{pos=L2,module=ModuleName, type=ObjSetName}},Rest}; parse_DefinedObjectSet([{typereference,L1,ObjSetName}|Rest]) -> {{objectset,L1,#'Externaltypereference'{pos=L1,module=resolve_module(ObjSetName), type=ObjSetName}},Rest}; parse_DefinedObjectSet(Tokens) -> parse_error(Tokens). parse_ObjectSetAssignment([{typereference,L1,ObjSetName}|Rest]) -> {Class,Rest2} = parse_DefinedObjectClass(Rest), case Rest2 of [{'::=',_}|Rest3] -> {ObjectSet,Rest4} = parse_ObjectSet(Rest3), {#typedef{pos=L1,name=ObjSetName, typespec=#'ObjectSet'{class=Class, set=ObjectSet}},Rest4}; _ -> parse_error(Rest2) end. %% parse_ObjectSet(Tokens) -> {Ret,Rest} %% Tokens = [Tok] %% Tok = tuple() %% Ret = {[],tuple()} | %% {list(),list()} | %% list() | %% ['EXTENSIONMARK'] | %% {'ALL',{'EXCEPT',Exclusions}} | %% {'SingleValue',SV} %% SV = list() | #'Externalvaluereference'{} | {definedvalue,term()} parse_ObjectSet([{'{',_}|Rest]) -> {ObjSetSpec,Rest2} = parse_ObjectSetSpec(Rest), case Rest2 of [{'}',_}|Rest3] -> {ObjSetSpec,Rest3}; _ -> parse_error(Rest2) end; parse_ObjectSet(Tokens) -> parse_error(Tokens). parse_ObjectSetSpec([{'...',_},{',',_}|Tokens0]) -> {Elements,Tokens} = parse_ElementSetSpec(Tokens0), {{element_set,empty,Elements},Tokens}; parse_ObjectSetSpec([{'...',_}|Tokens]) -> {{element_set,empty,empty},Tokens}; parse_ObjectSetSpec(Tokens) -> parse_ElementSetSpecs(Tokens). %% parse_ObjectSetElements(Tokens) -> {Result,Rest} %% Result ::= {'ObjectSetFromObjects',Objects,Name} | {pos,ObjectSet,Params} %% Objects ::= ReferencedObjects %% ReferencedObjects ::= (see parse_ReferencedObjects/1) %% Name ::= [FieldName] %% FieldName ::= {typefieldreference,atom()} | {valuefieldreference,atom()} %% ObjectSet ::= {objectset,integer(),#'Externaltypereference'{}} %% Params ::= list() (see parse_ActualParameterList/1) parse_ObjectSetElements(Tokens) -> Flist = [fun parse_ObjectSetFromObjects/1, fun parse_ParameterizedObjectSet/1], parse_or(Tokens, Flist). parse_ObjectClassFieldType(Tokens) -> {Class,Rest} = parse_DefinedObjectClass(Tokens), case Rest of [{'.',_}|Rest2] -> {FieldName,Rest3} = parse_FieldName(Rest2), OCFT = #'ObjectClassFieldType'{ classname=Class, class=Class,fieldname=FieldName}, {#type{def=OCFT},Rest3}; _ -> parse_error(Rest) end. parse_ObjectClassFieldValue(Tokens) -> parse_OpenTypeFieldVal(Tokens). parse_OpenTypeFieldVal(Tokens) -> {Type,Rest} = parse_Type(Tokens), case Rest of [{':',_}|Rest2] -> {Value,Rest3} = parse_Value(Rest2), {{opentypefieldvalue,Type,Value},Rest3}; _ -> parse_error(Rest) end. %% parse_ReferencedObjects(Tokens) -> {Result,Rest} %% Result ::= DefObject | DefObjSet | %% {po,DefObject,Params} | {pos,DefObjSet,Params} | %% %% DefObject ::= {object,#'Externaltypereference'{}} | %% {object,#'Externalvaluereference'{}} %% DefObjSet ::= {objectset,integer(),#'Externaltypereference'{}} %% Params ::= list() parse_ReferencedObjects(Tokens) -> Flist = [fun parse_DefinedObject/1, fun parse_DefinedObjectSet/1, fun parse_ParameterizedObjectSet/1], parse_or(Tokens, Flist). parse_ValueFromObject(Tokens) -> %% This production also matches ObjectFromObject. {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {valuefieldreference,_} -> {{'ValueFromObject',Objects,Name},Rest3}; _ -> parse_error(Rest2) end; _ -> parse_error(Rest) end. parse_TypeFromObject(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {typefieldreference,_FieldName} -> {#type{def={'TypeFromObject',Objects,Name}},Rest3}; _ -> parse_error(Rest2) end; _ -> parse_error(Rest) end. %% parse_ObjectSetFromObjects(Tokens) -> {Result,Rest} %% Result ::= {'ObjectSetFromObjects',Objects,Name} %% Objects ::= ReferencedObject (see parse_ReferencedObjects/1) %% Name ::= [FieldName] %% FieldName ::= {typefieldreference,atom()} | %% {valuefieldreference,atom()} parse_ObjectSetFromObjects(Tokens) -> {Objects,Rest} = parse_ReferencedObjects(Tokens), case Rest of [{'.',_}|Rest2] -> {Name,Rest3} = parse_FieldName(Rest2), case lists:last(Name) of {typefieldreference,_FieldName} -> {{'ObjectSetFromObjects',Objects,Name},Rest3}; _ -> parse_error(Rest2) end; _ -> parse_error(Rest) end. %% X.682 constraint specification parse_GeneralConstraint(Tokens) -> Flist = [fun parse_UserDefinedConstraint/1, fun parse_TableConstraint/1, fun parse_ContentsConstraint/1], parse_or(Tokens, Flist). parse_UserDefinedConstraint([{'CONSTRAINED',_},{'BY',_},{'{',_},{'}',_}|Rest])-> {{constrained_by,[]},Rest}; parse_UserDefinedConstraint([{'CONSTRAINED',_}, {'BY',_}, {'{',_}|Rest]) -> {Param,Rest2} = parse_UserDefinedConstraintParameter(Rest), case Rest2 of [{'}',_}|Rest3] -> {{constrained_by,Param},Rest3}; _ -> parse_error(Rest2) end; parse_UserDefinedConstraint(Tokens) -> parse_error(Tokens). parse_UserDefinedConstraintParameter(Tokens) -> parse_UserDefinedConstraintParameter(Tokens, []). parse_UserDefinedConstraintParameter(Tokens0, Acc) -> Flist = [fun parse_GovernorAndActualParameter/1, fun parse_ActualParameter/1], case parse_or(Tokens0, Flist) of {Result,[{',',_}|Tokens]} -> parse_UserDefinedConstraintParameter(Tokens, [Result|Acc]); {Result,Tokens} -> {lists:reverse(Acc, [Result]),Tokens} end. parse_GovernorAndActualParameter(Tokens) -> {Governor,Rest} = parse_Governor(Tokens), case Rest of [{':',_}|Rest2] -> {Params,Rest3} = parse_ActualParameter(Rest2), {{'Governor_Params',Governor,Params},Rest3}; _ -> parse_error(Rest) end. parse_TableConstraint(Tokens) -> Flist = [fun parse_ComponentRelationConstraint/1, fun parse_SimpleTableConstraint/1], parse_or(Tokens, Flist). parse_SimpleTableConstraint(Tokens) -> {ObjectSet,Rest} = parse_ObjectSet(Tokens), {{element_set,{simpletable,ObjectSet},none},Rest}. parse_ComponentRelationConstraint([{'{',_}|Rest]) -> {ObjectSet,Rest2} = parse_DefinedObjectSet(Rest), case Rest2 of [{'}',_},{'{',_}|Rest3] -> {AtNot,Rest4} = parse_AtNotationList(Rest3,[]), case Rest4 of [{'}',_}|Rest5] -> Ret = {element_set, {componentrelation,ObjectSet,AtNot}, none}, {Ret,Rest5}; _ -> parse_error(Rest4) end; _ -> parse_error(Rest2) end; parse_ComponentRelationConstraint(Tokens) -> parse_error(Tokens). parse_AtNotationList(Tokens,Acc) -> {AtNot,Rest} = parse_AtNotation(Tokens), case Rest of [{',',_}|Rest2] -> parse_AtNotationList(Rest2,[AtNot|Acc]); _ -> {lists:reverse(Acc, [AtNot]),Rest} end. parse_AtNotation([{'@',_},{'.',_}|Rest]) -> {CIdList,Rest2} = parse_ComponentIdList(Rest), {{innermost,CIdList},Rest2}; parse_AtNotation([{'@',_}|Rest]) -> {CIdList,Rest2} = parse_ComponentIdList(Rest), {{outermost,CIdList},Rest2}; parse_AtNotation(Tokens) -> parse_error(Tokens). parse_ComponentIdList(Tokens) -> parse_ComponentIdList(Tokens,[]). parse_ComponentIdList([#identifier{}=Id,{'.',_}|Rest], Acc) -> parse_ComponentIdList(Rest,[identifier2Extvalueref(Id)|Acc]); parse_ComponentIdList([#identifier{}=Id|Rest], Acc) -> {lists:reverse(Acc, [identifier2Extvalueref(Id)]),Rest}; parse_ComponentIdList(Tokens,_) -> parse_error(Tokens). parse_ContentsConstraint([{'CONTAINING',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), case Rest2 of [{'ENCODED',_},{'BY',_}|Rest3] -> {Value,Rest4} = parse_Value(Rest3), {{contentsconstraint,Type,Value},Rest4}; _ -> {{contentsconstraint,Type,[]},Rest2} end; parse_ContentsConstraint([{'ENCODED',_},{'BY',_}|Rest]) -> {Value,Rest2} = parse_Value(Rest), {{contentsconstraint,[],Value},Rest2}; parse_ContentsConstraint(Tokens) -> parse_error(Tokens). %% X.683 Parameterization of ASN.1 specifications parse_Governor(Tokens) -> Flist = [fun parse_Type/1, fun parse_DefinedObjectClass/1], parse_or(Tokens, Flist). parse_ActualParameter(Tokens) -> Flist = [fun parse_Type/1, fun parse_Value/1, fun parse_ValueSet/1, fun parse_DefinedObjectClass/1, fun parse_Object/1, fun parse_ObjectSet/1], parse_or(Tokens, Flist). %% parse_ParameterizedTypeAssignment(Tokens) -> Result %% Result = {#ptypedef{},Rest} | throw() parse_ParameterizedTypeAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Type,Rest4} = parse_Type(Rest3), {#ptypedef{pos=L1,name=Name,args=ParameterList,typespec=Type}, Rest4}; _ -> parse_error(Rest2) end. %% parse_ParameterizedValueAssignment(Tokens) -> Result %% Result = {#pvaluedef{},Rest} | throw() parse_ParameterizedValueAssignment([#identifier{pos=L1,val=Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Type,Rest3} = parse_Type(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {Value,Rest5} = parse_Value(Rest4), {#pvaluedef{pos=L1,name=Name,args=ParameterList,type=Type, value=Value},Rest5}; _ -> parse_error(Rest3) end. %% parse_ParameterizedValueSetTypeAssignment(Tokens) -> Result %% Result = {#pvaluesetdef{},Rest} | throw() parse_ParameterizedValueSetTypeAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Type,Rest3} = parse_Type(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {ValueSet,Rest5} = parse_ValueSet(Rest4), {#pvaluesetdef{pos=L1,name=Name,args=ParameterList, type=Type,valueset=ValueSet},Rest5}; _ -> parse_error(Rest3) end. %% parse_ParameterizedObjectClassAssignment(Tokens) -> Result %% Result = {#ptypedef{},Rest} | throw() parse_ParameterizedObjectClassAssignment([{typereference,L1,Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Class,Rest4} = parse_ObjectClass(Rest3), {#ptypedef{pos=L1,name=Name,args=ParameterList,typespec=Class}, Rest4}; _ -> parse_error(Rest2) end. %% parse_ParameterizedObjectAssignment(Tokens) -> Result %% Result = {#pobjectdef{},Rest} | throw() parse_ParameterizedObjectAssignment([#identifier{pos=L1,val=Name}|Rest]) -> {ParameterList,Rest2} = parse_ParameterList(Rest), {Class,Rest3} = parse_DefinedObjectClass(Rest2), case Rest3 of [{'::=',_}|Rest4] -> {Object,Rest5} = parse_Object(Rest4), {#pobjectdef{pos=L1,name=Name,args=ParameterList, class=Class,def=Object},Rest5}; _ -> parse_error(Rest3) end. %% parse_ParameterList(Tokens) -> Result %% Result = [Parameter] %% Parameter = {Governor,Reference} | Reference %% Governor = Type | DefinedObjectClass %% Type = #type{} %% DefinedObjectClass = #'Externaltypereference'{} %% Reference = #'Externaltypereference'{} | #'Externalvaluereference'{} parse_ParameterList([{'{',_}|Tokens]) -> parse_ParameterList(Tokens, []). parse_ParameterList(Tokens,Acc) -> {Parameter,Rest} = parse_Parameter(Tokens), case Rest of [{',',_}|Rest2] -> parse_ParameterList(Rest2, [Parameter|Acc]); [{'}',_}|Rest3] -> {lists:reverse(Acc, [Parameter]),Rest3}; _ -> parse_error(Rest) end. parse_Parameter(Tokens) -> Flist = [fun parse_ParamGovAndRef/1, fun parse_Reference/1], parse_or(Tokens, Flist). parse_ParamGovAndRef(Tokens) -> {ParamGov,Rest} = parse_ParamGovernor(Tokens), case Rest of [{':',_}|Rest2] -> {Ref,Rest3} = parse_Reference(Rest2), {{ParamGov,Ref},Rest3}; _ -> parse_error(Rest) end. parse_ParamGovernor(Tokens) -> Flist = [fun parse_Governor/1, fun parse_Reference/1], parse_or(Tokens, Flist). parse_SimpleDefinedType([{typereference,L1,ModuleName},{'.',_}, {typereference,_,TypeName}|Rest]) -> {#'Externaltypereference'{pos=L1,module=ModuleName, type=TypeName},Rest}; parse_SimpleDefinedType([Tref={typereference,_,_}|Rest]) -> {tref2Exttref(Tref),Rest}; parse_SimpleDefinedType(Tokens) -> parse_error(Tokens). parse_SimpleDefinedValue([{typereference,L1,ModuleName},{'.',_}, #identifier{val=Value}|Rest]) -> {{simpledefinedvalue,#'Externalvaluereference'{pos=L1,module=ModuleName, value=Value}},Rest}; parse_SimpleDefinedValue([#identifier{}=Id|Rest]) -> {{simpledefinedvalue,identifier2Extvalueref(Id)},Rest}; parse_SimpleDefinedValue(Tokens) -> parse_error(Tokens). parse_ParameterizedType(Tokens) -> %% May also be a parameterized class. {Type,Rest} = parse_SimpleDefinedType(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {#type{def={pt,Type,Params}},Rest2}. parse_ParameterizedValue(Tokens) -> %% May also be a parameterized object. {Value,Rest} = parse_SimpleDefinedValue(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{pv,Value,Params},Rest2}. parse_ParameterizedObjectSet(Tokens) -> {ObjectSet,Rest} = parse_DefinedObjectSet(Tokens), {Params,Rest2} = parse_ActualParameterList(Rest), {{pos,ObjectSet,Params},Rest2}. parse_ActualParameterList([{'{',_}|Rest]) -> parse_ActualParameterList(Rest,[]); parse_ActualParameterList(Tokens) -> parse_error(Tokens). parse_ActualParameterList(Tokens,Acc) -> {Parameter,Rest} = parse_ActualParameter(Tokens), case Rest of [{',',_}|Rest2] -> parse_ActualParameterList(Rest2,[Parameter|Acc]); [{'}',_}|Rest3] -> {lists:reverse(Acc, [Parameter]),Rest3}; _ -> parse_error(Rest) end. %% Test whether Token is allowed in a syntax list. is_word(Token) -> List = atom_to_list(Token), case not_allowed_word(List) of true -> false; false -> is_word_1(List) end. is_word_1([H|T]) -> check_first(H) andalso check_rest(T). not_allowed_word(Name) -> lists:member(Name,["BIT", "BOOLEAN", "CHARACTER", "CHOICE", "EMBEDDED", "END", "ENUMERATED", "EXTERNAL", "FALSE", "INSTANCE", "INTEGER", "INTERSECTION", "MINUS-INFINITY", "NULL", "OBJECT", "OCTET", "PLUS-INFINITY", "REAL", "SEQUENCE", "SET", "TRUE", "UNION"]). check_first(C) -> $A =< C andalso C =< $Z. check_rest([R|Rs]) when $A =< R, R =< $Z; R =:= $- -> check_rest(Rs); check_rest([]) -> true; check_rest(_) -> false. %%% %%% Parse alternative type lists for CHOICE. %%% parse_AlternativeTypeLists(Tokens0) -> {Root,Tokens1} = parse_AlternativeTypeList(Tokens0), case Tokens1 of [{',',_}|Tokens2] -> {ExtMarker,Tokens3} = parse_ExtensionAndException(Tokens2), {ExtAlts,Tokens4} = parse_ExtensionAdditionAlternatives(Tokens3), {_,Tokens} = parse_OptionalExtensionMarker(Tokens4, []), {Root++ExtMarker++ExtAlts,Tokens}; Tokens -> {Root,Tokens} end. parse_ExtensionAndException([{'...',L}|Tokens0]) -> {[#'EXTENSIONMARK'{pos=L}], case Tokens0 of [{'!',_}|Tokens1] -> {_,Tokens} = parse_ExceptionIdentification(Tokens1), Tokens; _ -> Tokens0 end}. parse_AlternativeTypeList([#identifier{}|_]=Tokens0) -> {AltType,Tokens} = parse_NamedType(Tokens0), parse_AlternativeTypeList_1(Tokens, [AltType]); parse_AlternativeTypeList(Tokens) -> parse_error(Tokens). parse_AlternativeTypeList_1([{',',_}|[#identifier{}|_]=Tokens0], Acc) -> {AltType,Tokens} = parse_NamedType(Tokens0), parse_AlternativeTypeList_1(Tokens, [AltType|Acc]); parse_AlternativeTypeList_1(Tokens, Acc) -> {lists:reverse(Acc),Tokens}. parse_ExtensionAdditionAlternatives([{',',_}|_]=Tokens0) -> parse_ExtensionAdditionAlternativesList(Tokens0, []); parse_ExtensionAdditionAlternatives(Tokens) -> {[],Tokens}. parse_ExtensionAdditionAlternativesList([{',',_}|Tokens1]=Tokens0, Acc) -> try parse_ExtensionAdditionAlternative(Tokens1) of {ExtAddAlt,Tokens2} -> parse_ExtensionAdditionAlternativesList(Tokens2, [ExtAddAlt|Acc]) catch throw:{asn1_error,_} -> {lists:append(lists:reverse(Acc)),Tokens0} end; parse_ExtensionAdditionAlternativesList(Tokens, Acc) -> {lists:append(lists:reverse(Acc)),Tokens}. parse_ExtensionAdditionAlternative([#identifier{}|_]=Tokens0) -> {NamedType,Tokens} = parse_NamedType(Tokens0), {[NamedType],Tokens}; parse_ExtensionAdditionAlternative([{'[',_},{'[',_}|Tokens0]) -> Tokens2 = case Tokens0 of [{number,_,_},{':',_}|Tokens1] -> Tokens1; _ -> Tokens0 end, {GroupList,Tokens3} = parse_AlternativeTypeList(Tokens2), case Tokens3 of [{']',_},{']',_}|Tokens] -> {GroupList,Tokens}; _ -> parse_error(Tokens3) end; parse_ExtensionAdditionAlternative(Tokens) -> parse_error(Tokens). %%% %%% End of parsing of alternative type lists. %%% parse_NamedType([#identifier{pos=L1,val=Idname}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {#'ComponentType'{pos=L1,name=Idname,typespec=Type,prop=mandatory},Rest2}; parse_NamedType(Tokens) -> parse_error(Tokens). %%% %%% Parse component type lists for SEQUENCE and SET. %%% parse_ComponentTypeLists(Tokens) -> parse_ComponentTypeLists(Tokens, []). parse_ComponentTypeLists([#identifier{}|_Rest0]=Tokens, Clist) -> {CompList,Rest1} = parse_ComponentTypeList(Tokens,[]), parse_ComponentTypeLists(Rest1,Clist++CompList); parse_ComponentTypeLists([{'COMPONENTS',_},{'OF',_}|_]=Tokens,Clist) -> {CompList,Rest1} = parse_ComponentTypeList(Tokens, []), parse_ComponentTypeLists(Rest1, Clist++CompList); parse_ComponentTypeLists([{',',L1},{'...',_},{'!',_}|Rest02],Clist0) when Clist0 =/= []-> {_,Rest03} = parse_ExceptionIdentification(Rest02), %% Exception info is currently thrown away parse_ComponentTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists([{',',_},{'...',L1}|Rest02],Clist0) when Clist0 =/= []-> parse_ComponentTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists([{'...',L1}|Rest02],Clist0) -> parse_ComponentTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]); parse_ComponentTypeLists(Tokens = [{'}',_L1}|_Rest02],Clist0) -> {Clist0,Tokens}; parse_ComponentTypeLists(Tokens, _) -> parse_error(Tokens). parse_ComponentTypeLists2(Tokens,Clist) -> {ExtAdd,Rest} = parse_ExtensionAdditions(Tokens,Clist), {Clist2,Rest2} = parse_OptionalExtensionMarker(Rest,lists:flatten(ExtAdd)), case Rest2 of [{',',_}|Rest3] -> {CompList,Rest4} = parse_ComponentTypeList(Rest3,[]), {Clist2 ++ CompList,Rest4}; _ -> {Clist2,Rest2} end. parse_OptionalExtensionMarker([{',',_},{'...',L1}|Rest],Clist)-> {Clist++[#'EXTENSIONMARK'{pos=L1}],Rest}; parse_OptionalExtensionMarker(Tokens,Clist) -> {Clist,Tokens}. parse_ComponentTypeList([{',',_}|[#identifier{}|_]=Tokens0], Acc) when Acc =/= [] -> {ComponentType,Tokens} = parse_ComponentType(Tokens0), parse_ComponentTypeList(Tokens, [ComponentType|Acc]); parse_ComponentTypeList([{',',_}|[{'COMPONENTS',_},{'OF',_}|_]=Tokens0], Acc) when Acc =/= [] -> {ComponentType,Tokens} = parse_ComponentType(Tokens0), parse_ComponentTypeList(Tokens, [ComponentType|Acc]); parse_ComponentTypeList(Tokens = [{'}',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ComponentTypeList(Tokens = [{']',_},{']',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ComponentTypeList(Tokens = [{',',_},{'...',_}|_],Acc) -> {lists:reverse(Acc),Tokens}; parse_ComponentTypeList(Tokens,[]) -> {ComponentType,Rest} = parse_ComponentType(Tokens), parse_ComponentTypeList(Rest,[ComponentType]); parse_ComponentTypeList(Tokens,_) -> parse_error(Tokens). parse_ExtensionAdditions(Tokens=[{',',_}|_],Clist) -> {ExtAddList,Rest2} = parse_ExtensionAdditionList(Tokens,[]), {Clist++ExtAddList,Rest2}; parse_ExtensionAdditions(Tokens,Clist) -> %% Empty {Clist,Tokens}. parse_ExtensionAdditionList([{',',_}|[#identifier{}|_]=Tokens0], Acc) -> {ComponentType,Tokens} = parse_ComponentType(Tokens0), parse_ExtensionAdditionList(Tokens, [ComponentType|Acc]); parse_ExtensionAdditionList([{',',_}|[{'COMPONENTS',_},{'OF',_}|_]=Tokens0], Acc) -> {ComponentType,Tokens} = parse_ComponentType(Tokens0), parse_ExtensionAdditionList(Tokens, [ComponentType|Acc]); parse_ExtensionAdditionList([{',',_},{'[',_},{'[',_}|Tokens], Acc) -> {ExtAddGroup,Rest2} = parse_ExtensionAdditionGroup(Tokens), parse_ExtensionAdditionList(Rest2,[ExtAddGroup|Acc]); parse_ExtensionAdditionList([{'}',_}|_]=Tokens, Acc) -> {lists:reverse(Acc),Tokens}; parse_ExtensionAdditionList([{',',_},{'...',_}|_]=Tokens, Acc) -> {lists:reverse(Acc),Tokens}; parse_ExtensionAdditionList(Tokens, _) -> parse_error(Tokens). parse_ExtensionAdditionGroup([{number,_,Num},{':',_}|Tokens]) -> parse_ExtensionAdditionGroup2(Tokens, Num); parse_ExtensionAdditionGroup(Tokens) -> parse_ExtensionAdditionGroup2(Tokens, undefined). parse_ExtensionAdditionGroup2(Tokens, Num) -> {CompTypeList,Rest} = parse_ComponentTypeList(Tokens,[]), case Rest of [{']',_},{']',_}|Rest2] -> {[{'ExtensionAdditionGroup',Num}|CompTypeList] ++ ['ExtensionAdditionGroupEnd'],Rest2}; _ -> parse_error(Rest) end. parse_ComponentType([{'COMPONENTS',_},{'OF',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {{'COMPONENTS OF',Type},Rest2}; parse_ComponentType(Tokens) -> Result = {NamedType,Rest} = parse_NamedType(Tokens), case Rest of [{'OPTIONAL',_}|Rest2] -> {NamedType#'ComponentType'{prop='OPTIONAL'},Rest2}; [{'DEFAULT',_}|Rest2] -> {Value,Rest21} = parse_Value(Rest2), {NamedType#'ComponentType'{prop={'DEFAULT',Value}},Rest21}; _ -> Result end. %%% %%% Parse ENUMERATED. %%% parse_Enumerations(Tokens0) -> {Root,Tokens1} = parse_Enumeration(Tokens0), case Tokens1 of [{',',_},{'...',_},{',',_}|Tokens2] -> {Ext,Tokens} = parse_Enumeration(Tokens2), {Root++['EXTENSIONMARK'|Ext],Tokens}; [{',',_},{'...',_}|Tokens] -> {Root++['EXTENSIONMARK'],Tokens}; _ -> case get(extensiondefault) of 'IMPLIED' -> {Root++['EXTENSIONMARK'],Tokens1}; _ -> {Root,Tokens1} end end. parse_Enumeration(Tokens0) -> {Item,Tokens} = parse_EnumerationItem(Tokens0), parse_Enumeration_1(Tokens, [Item]). parse_Enumeration_1([{',',_}|Tokens1]=Tokens0, Acc) -> try parse_EnumerationItem(Tokens1) of {Item,Tokens} -> parse_Enumeration_1(Tokens, [Item|Acc]) catch throw:{asn1_error,_} -> {lists:reverse(Acc),Tokens0} end; parse_Enumeration_1(Tokens, Acc) -> {lists:reverse(Acc),Tokens}. parse_EnumerationItem([#identifier{},{'(',_}|_]=Tokens) -> parse_NamedNumber(Tokens); parse_EnumerationItem([#identifier{val=Id}|Tokens]) -> {Id,Tokens}; parse_EnumerationItem(Tokens) -> parse_error(Tokens). %%% %%% End of parsing of ENUMERATED. %%% parse_NamedNumberList(Tokens) -> parse_NamedNumberList(Tokens, []). parse_NamedNumberList(Tokens, Acc) -> {NamedNum,Rest} = parse_NamedNumber(Tokens), case Rest of [{',',_}|Rest2] -> parse_NamedNumberList(Rest2,[NamedNum|Acc]); _ -> {lists:reverse(Acc, [NamedNum]),Rest} end. parse_NamedNumber([#identifier{val=Name},{'(',_}|Rest]) -> Flist = [fun parse_SignedNumber/1, fun parse_DefinedValue/1], case parse_or(Rest, Flist) of {NamedNum,[{')',_}|Rest2]} -> {{'NamedNumber',Name,NamedNum},Rest2}; _ -> parse_error(Rest) end; parse_NamedNumber(Tokens) -> parse_error(Tokens). parse_SignedNumber([{number,_,Value}|Rest]) -> {Value,Rest}; parse_SignedNumber(Tokens) -> parse_error(Tokens). parse_Tag([{'[',_}|Rest]) -> {Class,Rest2} = parse_Class(Rest), {ClassNumber,Rest3} = case Rest2 of [{number,_,Num}|Rest21] -> {Num,Rest21}; _ -> parse_DefinedValue(Rest2) end, case Rest3 of [{']',_}|Rest4] -> {#tag{class=Class,number=ClassNumber},Rest4}; _ -> parse_error(Rest3) end. parse_Class([{'UNIVERSAL',_}|Rest]) -> {'UNIVERSAL',Rest}; parse_Class([{'APPLICATION',_}|Rest]) -> {'APPLICATION',Rest}; parse_Class([{'PRIVATE',_}|Rest]) -> {'PRIVATE',Rest}; parse_Class(Tokens) -> {'CONTEXT',Tokens}. %% parse_Value(Tokens) -> Ret %% Tokens = [Tok] %% Tok = tuple() %% Ret = term() parse_Value(Tokens) -> Flist = [fun parse_BuiltinValue/1, fun parse_ValueFromObject/1, fun parse_DefinedValue/1], parse_or(Tokens, Flist). parse_BuiltinValue([{bstring,_,Bstr}|Rest]) -> {{bstring,Bstr},Rest}; parse_BuiltinValue([{hstring,_,Hstr}|Rest]) -> {{hstring,Hstr},Rest}; parse_BuiltinValue([{'{',_},{'}',_}|Rest]) -> {[],Rest}; parse_BuiltinValue(Tokens = [{'{',_}|_Rest]) -> Flist = [ fun parse_SequenceOfValue/1, fun parse_SequenceValue/1, fun parse_ObjectIdentifierValue/1], parse_or(Tokens, Flist); parse_BuiltinValue([#identifier{val=IdName},{':',_}|Rest]) -> {Value,Rest2} = parse_Value(Rest), {{'CHOICE',{IdName,Value}},Rest2}; parse_BuiltinValue([{'NULL',_},{':',_}|_]=Tokens) -> parse_ObjectClassFieldValue(Tokens); parse_BuiltinValue([{'NULL',_}|Rest]) -> {'NULL',Rest}; parse_BuiltinValue([{'TRUE',_}|Rest]) -> {true,Rest}; parse_BuiltinValue([{'FALSE',_}|Rest]) -> {false,Rest}; parse_BuiltinValue([{'PLUS-INFINITY',_}|Rest]) -> {'PLUS-INFINITY',Rest}; parse_BuiltinValue([{'MINUS-INFINITY',_}|Rest]) -> {'MINUS-INFINITY',Rest}; parse_BuiltinValue([{cstring,_,Cstr}|Rest]) -> {Cstr,Rest}; parse_BuiltinValue([{number,_,Num}|Rest]) -> {Num,Rest}; parse_BuiltinValue(Tokens) -> parse_ObjectClassFieldValue(Tokens). parse_DefinedValue(Tokens) -> Flist = [fun parse_ParameterizedValue/1, fun parse_DefinedValue2/1], parse_or(Tokens, Flist). parse_DefinedValue2([{typereference,L1,Tname}, {'.',_}, #identifier{val=Idname}|Rest]) -> {#'Externalvaluereference'{pos=L1,module=Tname,value=Idname},Rest}; %% valuereference parse_DefinedValue2([#identifier{}=Id|Rest]) -> {identifier2Extvalueref(Id),Rest}; parse_DefinedValue2(Tokens) -> parse_error(Tokens). parse_SequenceValue([{'{',_}|Tokens]) -> parse_SequenceValue(Tokens, []). parse_SequenceValue([#identifier{pos=Pos,val=IdName}|Rest],Acc) -> {Value,Rest2} = parse_Value(Rest), SeqTag = #seqtag{pos=Pos,module=get(asn1_module),val=IdName}, case Rest2 of [{',',_}|Rest3] -> parse_SequenceValue(Rest3, [{SeqTag,Value}|Acc]); [{'}',_}|Rest3] -> {lists:reverse(Acc, [{SeqTag,Value}]),Rest3}; _ -> parse_error(Rest2) end; parse_SequenceValue(Tokens,_Acc) -> parse_error(Tokens). parse_SequenceOfValue([{'{',_}|Tokens]) -> parse_SequenceOfValue(Tokens, []). parse_SequenceOfValue(Tokens,Acc) -> {Value,Rest2} = parse_Value(Tokens), case Rest2 of [{',',_}|Rest3] -> parse_SequenceOfValue(Rest3,[Value|Acc]); [{'}',_}|Rest3] -> {lists:reverse(Acc, [Value]),Rest3}; _ -> parse_error(Rest2) end. parse_ValueSetTypeAssignment([{typereference,L1,Name}|Rest]) -> {Type,Rest2} = parse_Type(Rest), case Rest2 of [{'::=',_}|Rest3] -> {ValueSet,Rest4} = parse_ValueSet(Rest3), {#valuedef{pos=L1,name=Name,type=Type,value=ValueSet, module=get(asn1_module)},Rest4}; _ -> parse_error(Rest2) end. parse_ValueSet([{'{',_}|Rest]) -> {Elems,Rest2} = parse_ElementSetSpecs(Rest), case Rest2 of [{'}',_}|Rest3] -> {{valueset,Elems},Rest3}; _ -> parse_error(Rest2) end; parse_ValueSet(Tokens) -> parse_error(Tokens). parse_ValueAssignment([#identifier{pos=L1,val=IdName}|Rest]) -> {Type,Rest2} = parse_Type(Rest), case Rest2 of [{'::=',_}|Rest3] -> {Value,Rest4} = parse_Value(Rest3), {#valuedef{pos=L1,name=IdName,type=Type,value=Value, module=get(asn1_module)},Rest4}; _ -> parse_error(Rest2) end. %% SizeConstraint parse_SubtypeElements([{'SIZE',_}|Tokens]) -> {Constraint,Rest} = parse_Constraint(Tokens), {{'SizeConstraint',Constraint#constraint.c},Rest}; %% PermittedAlphabet parse_SubtypeElements([{'FROM',_}|Tokens]) -> {Constraint,Rest} = parse_Constraint(Tokens), {{'PermittedAlphabet',Constraint#constraint.c},Rest}; %% InnerTypeConstraints parse_SubtypeElements([{'WITH',_},{'COMPONENT',_}|Tokens]) -> {Constraint,Rest} = parse_Constraint(Tokens), {{'WITH COMPONENT',Constraint},Rest}; parse_SubtypeElements([{'WITH',_},{'COMPONENTS',_},{'{',_},{'...',_},{',',_}|Tokens]) -> {Constraint,Rest} = parse_TypeConstraints(Tokens), case Rest of [{'}',_}|Rest2] -> {{'WITH COMPONENTS',{'PartialSpecification',Constraint}},Rest2}; _ -> parse_error(Rest) end; parse_SubtypeElements([{'WITH',_},{'COMPONENTS',_},{'{',_}|Tokens]) -> {Constraint,Rest} = parse_TypeConstraints(Tokens), case Rest of [{'}',_}|Rest2] -> {{'WITH COMPONENTS',{'FullSpecification',Constraint}},Rest2}; _ -> parse_error(Rest) end; parse_SubtypeElements([{'PATTERN',_}|Tokens]) -> {Value,Rest} = parse_Value(Tokens), {{pattern,Value},Rest}; parse_SubtypeElements(Tokens) -> Flist = [fun parse_ContainedSubtype/1, fun parse_Value/1, fun parse_MIN/1, fun parse_Type/1], case parse_or(Tokens, Flist) of {#type{},_}=Result -> Result; {Lower,[{'..',_}|Rest]} -> {Upper,Rest2} = parse_UpperEndpoint(Rest), {{'ValueRange',{Lower,Upper}},Rest2}; {Lower,[{'<',_},{'..',_}|Rest]} -> {Upper,Rest2} = parse_UpperEndpoint(Rest), {{'ValueRange',{{gt,Lower},Upper}},Rest2}; {Res={'ContainedSubtype',_Type},Rest} -> {Res,Rest}; {Value,Rest} -> {{'SingleValue',Value},Rest} end. parse_ContainedSubtype([{'INCLUDES',_}|Rest]) -> {Type,Rest2} = parse_Type(Rest), {{'ContainedSubtype',Type},Rest2}; parse_ContainedSubtype(Tokens) -> parse_error(Tokens). parse_UpperEndpoint([{'<',_}|Rest]) -> parse_UpperEndpoint(lt,Rest); parse_UpperEndpoint(Tokens) -> parse_UpperEndpoint(false,Tokens). parse_UpperEndpoint(Lt,Tokens) -> Flist = [fun parse_MAX/1, fun parse_Value/1], case parse_or(Tokens, Flist) of {Value,Rest2} when Lt =:= lt -> {{lt,Value},Rest2}; {Value,Rest2} -> {Value,Rest2} end. parse_MIN([{'MIN',_}|T]) -> {'MIN',T}; parse_MIN(Tokens) -> parse_error(Tokens). parse_MAX([{'MAX',_}|T]) -> {'MAX',T}; parse_MAX(Tokens) -> parse_error(Tokens). parse_TypeConstraints(Tokens) -> parse_TypeConstraints(Tokens, []). parse_TypeConstraints([#identifier{}|Rest], Acc) -> {ComponentConstraint,Rest2} = parse_ComponentConstraint(Rest), case Rest2 of [{',',_}|Rest3] -> parse_TypeConstraints(Rest3, [ComponentConstraint|Acc]); _ -> {lists:reverse(Acc, [ComponentConstraint]),Rest2} end; parse_TypeConstraints(Tokens, _) -> parse_error(Tokens). parse_ComponentConstraint(Tokens = [{'(',_}|_Rest]) -> {ValueConstraint,Rest2} = parse_Constraint(Tokens), {PresenceConstraint,Rest3} = parse_PresenceConstraint(Rest2), {{ValueConstraint,PresenceConstraint},Rest3}; parse_ComponentConstraint(Tokens) -> {PresenceConstraint,Rest} = parse_PresenceConstraint(Tokens), {{asn1_empty,PresenceConstraint},Rest}. parse_PresenceConstraint([{'PRESENT',_}|Rest]) -> {'PRESENT',Rest}; parse_PresenceConstraint([{'ABSENT',_}|Rest]) -> {'ABSENT',Rest}; parse_PresenceConstraint([{'OPTIONAL',_}|Rest]) -> {'OPTIONAL',Rest}; parse_PresenceConstraint(Tokens) -> {asn1_empty,Tokens}. merge_constraints(Clist) -> merge_constraints(Clist, [], []). merge_constraints([#constraint{c=C,e=E}|T], Cacc0, Eacc0) -> Eacc = case E of undefined -> Eacc0; E -> [E|Eacc0] end, Cacc = [C|Cacc0], merge_constraints(T, Cacc, Eacc); merge_constraints([], Cacc, []) -> lists:reverse(Cacc); merge_constraints([], Cacc, Eacc) -> lists:reverse(Cacc) ++ [{element_set,{'Errors',Eacc},none}]. get_line({Token,Pos,_}) when is_integer(Pos), is_atom(Token) -> Pos; get_line({Token,Pos}) when is_integer(Pos),is_atom(Token) -> Pos. get_token({valuefieldreference,_,FieldName}) -> list_to_atom([$&|atom_to_list(FieldName)]); get_token({typefieldreference,_,FieldName}) -> list_to_atom([$&|atom_to_list(FieldName)]); get_token({Token,Pos,Value}) when is_integer(Pos), is_atom(Token) -> Value; get_token({'$end',Pos}) when is_integer(Pos) -> 'END-OF-FILE'; get_token({Token,Pos}) when is_integer(Pos),is_atom(Token) -> Token. tref2Exttref(#typereference{pos=Pos,val=Name}) -> #'Externaltypereference'{pos=Pos, module=resolve_module(Name), type=Name}. tref2Exttref(Pos,Name) -> #'Externaltypereference'{pos=Pos, module=resolve_module(Name), type=Name}. identifier2Extvalueref(#identifier{pos=Pos,val=Name}) -> #'Externalvaluereference'{pos=Pos, module=resolve_module(Name), value=Name}. parse_error(Tokens) -> throw({asn1_error,{parse_error,Tokens}}).