aboutsummaryrefslogblamecommitdiffstats
path: root/lib/asn1/src/asn1ct_parser2.erl
blob: 4a576ce2d2200694406aba1994f9402f9f05ee72 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
                              

                   
  
                                                        
  




                                                                      
  



                                                                         
  







                             

                                           

                               
 










                                                                              
                                       









                                                                        






                                






























                                                                            


                                                                   



                                                    

                                                               





                                                         
                                                           








                                                                                  


                                                        






























































































































































































































































































































                                                                                                                                





                                                                    

                          







                                                                                     






                                                                         
                                                                          














                                                                         

                                                          

































                                                                                 

                                                           
           

                                                                             



                                                                          



                                                                      

                    

                                                                              














                                                                            







                                                                                  



                                                                         










                                                                                   





                                                                   
                                                                        




                                                                          

                                                                                  








                                                                         







                                                                                  



                                                                         











                                                                              
























                                                                               














                                                                          


                                                                            

                                                                            












                                                                                             

                                                            














                                                                          


                                                                       

                                                                       














                                                                          











                                                                     
                                         
















                                                                     
                                                                                  



                                                                         
                                                                                  









                                                                                         

                                                                                 













                                                                              








                                                                            
                                                          
                              


                                                                      


                      


























































































                                                                         




                                                                  
                                                            
                                    
                                                  
            
                                               



                                                      
                                      














                                                  
                  
                                 







                                                 
                  
                                 
            

                                         








                                                         
                  
                                        







                                                        
                  
                       
                  
                                        
        

                                                












                                                                
                                                  















































                                                                                                      









                                                                             

                                                                 























































































                                                                            

                                                         















































































































































































































































































































































































































                                                                                            
                                                                                     















































                                                                           




                                                      






























































































































                                                                             












































































































































                                                                                
                                                      







                                                           



                                                               






































































































































































































































                                                                                     
                                                  













































































































































































































                                                                            































                                                                                           
 
 
 






















































                                                                                                       
                


                                                             
            
















































                                                                             

    











                                                                  
    
 












                                                                                   
 
















                                                                                









                                                                              






























                                                                                         
            
                          

        



                                                                
 
 












                                                                                              
                                                       














































                                                                                           
                


                                                             
            

                                                                           

        




                                                        
                                                        






                                                                       
                  












                                                             


                                                                       


                                                                 
                                                                                       


                                                    


                                                                          


                                                    
                                                                      

                          


                                                                 


                                          
                                                               

                          
                                                                      


                                                       
                                 














































































































































                                                                                      
                                                          
                                      
                                                                 

                          
                                                             
                          
                                                         







































































































































































































                                                                                        


                                     







                                                            
                        

                                                                




















































                                                                                   
                                                         



                                        
                                                         



                                                        
                                                          









                                                                 
%% vim: tabstop=8:shiftwidth=4
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
%%
-module(asn1ct_parser2).

-export([parse/1]).
-include("asn1_records.hrl").

%% Only used internally within this module.
-record(typereference, {pos,val}).
-record(constraint, {c,e}).
-record(identifier, {pos,val}).

%% parse all types in module
parse(Tokens) ->
    case catch parse_ModuleDefinition(Tokens) of
	{'EXIT',Reason} ->
	    {error,{{undefined,get(asn1_module),
		    [internal,error,'when',parsing,module,definition,Reason]},
		    hd(Tokens)}};
	{asn1_error,Reason} ->
	    {error,{Reason,hd(Tokens)}};
	{ModuleDefinition,Rest1} ->
	    {Types,Rest2} = parse_AssignmentList(Rest1),
	    clean_process_dictionary(),
	    case Rest2 of
		[{'END',_}|_Rest3] ->
		    {ok,ModuleDefinition#module{typeorval = Types}};
		_  ->
		    {error,{{get_line(hd(Rest2)),get(asn1_module),
			     [got,get_token(hd(Rest2)),expected,'END']},
			    hd(Rest2)}}
	    end
    end.

clean_process_dictionary() ->
    Mod = erase(asn1_module),
    _ = erase({Mod,imports}),
    _ = erase(tagdefault),
    _ = erase(extensiondefault),
    ok.

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;
	       _ ->
		   throw({asn1_error,{get_line(hd(Rest02)),get(asn1_module),
				      [got,get_token(hd(Rest02)),
				       expected,'DEFINITIONS']}})
	   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};
	_ -> throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module),
				[got,get_token(hd(Rest3)),expected,"::= BEGIN"]}})
    end;
parse_ModuleDefinition(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,typereference]}}).
    
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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,';']}})
    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([Symbol|Acc]),Rest2}
    end.

parse_Symbol(Tokens) ->
    parse_Reference(Tokens).

parse_Reference([{typereference,L1,TrefName},{'{',_L2},{'}',_L3}|Rest]) ->
%    {Tref,Rest};
    {tref2Exttref(L1,TrefName),Rest};
parse_Reference([Tref1 = {typereference,_,_},{'.',_},Tref2 = {typereference,_,_},
		 {'{',_L2},{'}',_L3}|Rest]) ->
%    {{Tref1,Tref2},Rest};
    {{tref2Exttref(Tref1),tref2Exttref(Tref2)},Rest};
parse_Reference([Tref = {typereference,_L1,_TrefName}|Rest]) ->
    {tref2Exttref(Tref),Rest};
parse_Reference([Vref = {identifier,_L1,_VName},{'{',_L2},{'}',_L3}|Rest]) ->
    {identifier2Extvalueref(Vref),Rest};
parse_Reference([Vref = {identifier,_L1,_VName}|Rest]) ->
    {identifier2Extvalueref(Vref),Rest};
parse_Reference(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[typereference,identifier]]}}).

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};
	Rest3 ->
	    throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module),
			       [got,get_token(hd(Rest3)),expected,';']}})
    end;
parse_Imports(Tokens) ->
    {{imports,[]},Tokens}.

parse_SymbolsFromModuleList(Tokens) ->
    parse_SymbolsFromModuleList(Tokens,[]).

parse_SymbolsFromModuleList(Tokens,Acc) ->
    {SymbolsFromModule,Rest} = parse_SymbolsFromModule(Tokens),
    case (catch parse_SymbolsFromModule(Rest)) of 
	{Sl,_Rest2} when is_record(Sl,'SymbolsFromModule') ->
	    parse_SymbolsFromModuleList(Rest,[SymbolsFromModule|Acc]);
	_  ->
	    {lists:reverse([SymbolsFromModule|Acc]),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},Tref = {typereference,_,Name},Ref={identifier,_L2,_Id},C={',',_}|Rest2] ->
	    NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList),
	    {#'SymbolsFromModule'{symbols=NewSymbolList,
				  module=tref2Exttref(Tref)},[Ref,C|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},Tref = {typereference,_,Name},Ref = {identifier,_L2,_Id},From = {'FROM',_}|Rest2] ->
	    NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList),
	    {#'SymbolsFromModule'{symbols=NewSymbolList,
				  module=tref2Exttref(Tref)},[Ref,From|Rest2]};
	[{'FROM',_L1},Tref = {typereference,_,Name},{identifier,_L2,_Id}|Rest2] ->
	    NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList),
	    {#'SymbolsFromModule'{symbols=NewSymbolList,
				  module=tref2Exttref(Tref)},Rest2}; 
	[{'FROM',_L1},Tref = {typereference,_,Name},Brace = {'{',_}|Rest2] ->
	    {_ObjIdVal,Rest3} = parse_ObjectIdentifierValue([Brace|Rest2]), % value not used yet, fix me
	    NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList),
	    {#'SymbolsFromModule'{symbols=NewSymbolList,
				  module=tref2Exttref(Tref)},Rest3}; 
	[{'FROM',_L1},Tref = {typereference,_,Name}|Rest2] ->
	    NewSymbolList = lists:map(SetRefModuleName(Name),SymbolList),
	    {#'SymbolsFromModule'{symbols=NewSymbolList,
				  module=tref2Exttref(Tref)},Rest2};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest)),get(asn1_module),
			       [got,get_token(hd(Rest)),expected,
				['FROM typerefernece identifier ,',
				 'FROM typereference identifier',
				 'FROM typereference {',
				 'FROM typereference']]}})
    end.

parse_ObjectIdentifierValue([{'{',_}|Rest]) ->
    parse_ObjectIdentifierValue(Rest,[]).

parse_ObjectIdentifierValue([{number,_,Num}|Rest],Acc) ->
    parse_ObjectIdentifierValue(Rest,[Num|Acc]);
parse_ObjectIdentifierValue([{identifier,_,Id},{'(',_}, {number,_,Num}, {')',_}|Rest],Acc) ->
    parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,Num}|Acc]);
parse_ObjectIdentifierValue([{identifier,_,Id},{'(',_}, {identifier,_,Id2}, {')',_}|Rest],Acc) ->
    parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,Id2}|Acc]);
parse_ObjectIdentifierValue([{identifier,_,Id},{'(',_}, {typereference,_,Tref},{'.',_},{identifier,_,Id2}, {')',_}|Rest],Acc) ->
    parse_ObjectIdentifierValue(Rest,[{'NamedNumber',Id,{'ExternalValue',Tref,Id2}}|Acc]);
parse_ObjectIdentifierValue([Id = {identifier,_,_}|Rest],Acc) ->
    parse_ObjectIdentifierValue(Rest,[identifier2Extvalueref(Id)|Acc]);
parse_ObjectIdentifierValue([{'}',_}|Rest],Acc) ->
    {lists:reverse(Acc),Rest};
parse_ObjectIdentifierValue([H|_T],_Acc) ->
    throw({asn1_error,{get_line(H),get(asn1_module),
		       [got,get_token(H),expected,
			['{ some of the following }',number,'identifier ( number )',
			 'identifier ( identifier )',
			 'identifier ( typereference.identifier)',identifier]]}}).
    
parse_AssignmentList(Tokens = [{'END',_}|_Rest]) ->
    {[],Tokens};
parse_AssignmentList(Tokens = [{'$end',_}|_Rest]) ->
    {[],Tokens};
parse_AssignmentList(Tokens) ->
    parse_AssignmentList(Tokens,[]).

parse_AssignmentList(Tokens= [{'END',_}|_Rest],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_AssignmentList(Tokens= [{'$end',_}|_Rest],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_AssignmentList(Tokens,Acc) ->
    case (catch parse_Assignment(Tokens)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	{asn1_error,R} ->
%	    [H|T] = Tokens,
	    throw({error,{R,hd(Tokens)}});
	{Assignment,Rest} ->
	    parse_AssignmentList(Rest,[Assignment|Acc])
    end.

parse_Assignment(Tokens) ->
    Flist = [fun parse_TypeAssignment/1,
	     fun parse_ValueAssignment/1,
	     fun parse_ObjectClassAssignment/1,
	     fun parse_ObjectAssignment/1,
	     fun parse_ObjectSetAssignment/1,
	     fun parse_ParameterizedAssignment/1,
	     fun parse_ValueSetTypeAssignment/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	{asn1_assignment_error,Reason} ->
	    throw({asn1_error,Reason});
	Result ->
	    Result
    end.


parse_or(Tokens,Flist) ->
	parse_or(Tokens,Flist,[]).

parse_or(_Tokens,[],ErrList) ->
    case ErrList of
	[] ->
	    throw({asn1_error,{parse_or,ErrList}});
	L when is_list(L) ->
	    %% chose to throw 1) the error with the highest line no,
	    %% 2) the last error which is not a asn1_assignment_error or
	    %% 3) the last error.
	    throw(prioritize_error(ErrList))
    end;
parse_or(Tokens,[Fun|Frest],ErrList) ->
    case (catch Fun(Tokens)) of
	Exit = {'EXIT',_Reason} ->
	    parse_or(Tokens,Frest,[Exit|ErrList]);
	AsnErr = {asn1_error,_} ->
	    parse_or(Tokens,Frest,[AsnErr|ErrList]);
	AsnAssErr = {asn1_assignment_error,_} ->
	    parse_or(Tokens,Frest,[AsnAssErr|ErrList]);
	Result = {_,L} when is_list(L) ->
	    Result;
	Error  ->
	    parse_or(Tokens,Frest,[Error|ErrList])
    end.

parse_or_tag(Tokens,Flist) ->
	parse_or_tag(Tokens,Flist,[]).

parse_or_tag(_Tokens,[],ErrList) ->
    case ErrList of
	[] ->
	    throw({asn1_error,{parse_or_tag,ErrList}});
	L when is_list(L) ->
	    %% chose to throw 1) the error with the highest line no,
	    %% 2) the last error which is not a asn1_assignment_error or
	    %% 3) the last error.
	    throw(prioritize_error(ErrList))
    end;
parse_or_tag(Tokens,[{Tag,Fun}|Frest],ErrList) when is_function(Fun) ->
    case (catch Fun(Tokens)) of
	Exit = {'EXIT',_Reason} ->
	    parse_or_tag(Tokens,Frest,[Exit|ErrList]);
	AsnErr = {asn1_error,_} ->
	    parse_or_tag(Tokens,Frest,[AsnErr|ErrList]);
	AsnAssErr = {asn1_assignment_error,_} ->
	    parse_or_tag(Tokens,Frest,[AsnAssErr|ErrList]);
	{ParseRes,Rest} when is_list(Rest) ->
	    {{Tag,ParseRes},Rest};
	Error  ->
	    parse_or_tag(Tokens,Frest,[Error|ErrList])
    end.

parse_TypeAssignment([{typereference,L1,Tref},{'::=',_}|Rest]) ->	
    {Type,Rest2} = parse_Type(Rest),
    {#typedef{pos=L1,name=Tref,typespec=Type},Rest2};
parse_TypeAssignment([H1,H2|_Rest]) ->
    throw({asn1_assignment_error,{get_line(H1),get(asn1_module),
				  [got,[get_token(H1),get_token(H2)], expected,
				   typereference,'::=']}});
parse_TypeAssignment([H|_T]) ->
    throw({asn1_assignment_error,{get_line(H),get(asn1_module),
				  [got,get_token(H),expected,
				   typereference]}}).

%% parse_Type(Tokens) -> Ret
%%
%% Tokens = [Tok]
%% Tok    = tuple()
%% Ret    = #type{}
%%
parse_Type(Tokens) ->
    {Tag,Rest3} = case Tokens of
		      [Lbr= {'[',_}|Rest] ->
			  parse_Tag([Lbr|Rest]);
		      Rest-> {[],Rest}
		  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} = case (catch parse_or(Rest4,Flist)) of
		      {'EXIT',Reason} ->
			  exit(Reason);
			AsnErr = {asn1_error,_Reason} ->
			 throw(AsnErr);
		      Result ->
			  Result
		  end,
    case hd(Rest5) of
	{'(',_} ->
	    {Constraints,Rest6} = parse_Constraints(Rest5),
	    if is_record(Type,type) ->
		    {Type#type{constraint=merge_constraints(Constraints),
			       tag=Tag2},Rest6};
	       true ->
		    {#type{def=Type,constraint=merge_constraints(Constraints),
			   tag=Tag2},Rest6}
	    end;
	_ ->
	    if is_record(Type,type) ->
		    {Type#type{tag=Tag2},Rest5};
	       true ->
		    {#type{def=Type,tag=Tag2},Rest5}
	    end
    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};
		_ ->
		    throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module),
				       [got,get_token(hd(Rest3)),expected,'}']}})
	    end;
	 _ ->
	    {{'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]) ->
    {AlternativeTypeLists,Rest2} = parse_AlternativeTypeLists(Rest),
    AlternativeTypeLists1 =
	lists:filter(fun(#'ExtensionAdditionGroup'{}) -> false;
			('ExtensionAdditionGroupEnd') -> false;
			(_) -> true
		     end,AlternativeTypeLists),
    case Rest2 of
	[{'}',_}|Rest3] ->
	    AlternativeTypeLists2 =
		case {[Ext||Ext = #'EXTENSIONMARK'{} <- AlternativeTypeLists1],
		      get(extensiondefault)} of
		    {[],'IMPLIED'} ->  AlternativeTypeLists1 ++ [#'EXTENSIONMARK'{}];
		    _ -> AlternativeTypeLists1
		end,

	    {#type{def={'CHOICE',AlternativeTypeLists2}},Rest3};
	_  ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    end;
parse_BuiltinType([{'EMBEDDED',_},{'PDV',_}|Rest]) ->
    {#type{def='EMBEDDED PDV'},Rest};
parse_BuiltinType([{'ENUMERATED',_},{'{',_}|Rest]) ->
    {Enumerations,Rest2} = parse_Enumerations(Rest,get(extensiondefault)),
    case Rest2 of
	[{'}',_}|Rest3] ->
	    {#type{def={'ENUMERATED',Enumerations}},Rest3};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    end;
parse_BuiltinType([{'EXTERNAL',_}|Rest]) ->
    {#type{def='EXTERNAL'},Rest};

% InstanceOfType
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(Tokens) ->
    
parse_BuiltinType([{'INTEGER',_}|Rest]) ->
    case Rest of 
	[{'{',_}|Rest2] ->
	    {NamedNumberList,Rest3} = parse_NamedNumberList(Rest2),
	    case Rest3 of
		[{'}',_}|Rest4] ->
		    {#type{def={'INTEGER',NamedNumberList}},Rest4};
		_ ->
		    throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module),
				       [got,get_token(hd(Rest3)),expected,'}']}})
	    end;
	 _ ->
	    {#type{def='INTEGER'},Rest}
    end;
parse_BuiltinType([{'NULL',_}|Rest]) ->
    {#type{def='NULL'},Rest};

% ObjectClassFieldType fix me later

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};
		_  ->
		    throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module),
			       [got,get_token(hd(Rest3)),expected,'}']}})
	    end
% 	_ -> % Seq case 4,17-19,23-26 will fail here
% 	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
% 			       [got,get_token(hd(Rest2)),expected,'}']}})
    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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    end;

parse_BuiltinType([{'SEQUENCE',_},{'OF',_},Id={identifier,_,_},Lt={'<',_}|Rest]) ->
%% TODO: take care of the identifier for something useful
    {Type,Rest2} = parse_SelectionType([Id,Lt|Rest]),
    {#type{def={'SEQUENCE OF',#type{def=Type,tag=[]}}},Rest2};

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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    end;

parse_BuiltinType([{'SET',_},{'OF',_},Id={identifier,_,_},Lt={'<',_}|Rest]) ->
%% TODO: take care of the identifier for something useful
    {Type,Rest2} = parse_SelectionType([Id,Lt|Rest]),
    {#type{def={'SET OF',#type{def=Type,tag=[]}}},Rest2};


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};

%% The so called Useful types
parse_BuiltinType([{'GeneralizedTime',_}|Rest]) ->
    {#type{def='GeneralizedTime'},Rest};
parse_BuiltinType([{'UTCTime',_}|Rest]) ->
    {#type{def='UTCTime'},Rest};
parse_BuiltinType([{'ObjectDescriptor',_}|Rest]) ->
    {#type{def='ObjectDescriptor'},Rest};

%% For compatibility with old standard
parse_BuiltinType([{'ANY',_},{'DEFINED',_},{'BY',_},{identifier,_,Id}|Rest]) ->
    {#type{def={'ANY_DEFINED_BY',Id}},Rest};
parse_BuiltinType([{'ANY',_}|Rest]) ->
    {#type{def='ANY'},Rest};

parse_BuiltinType(Tokens) ->
    parse_ObjectClassFieldType(Tokens).
%    throw({asn1_error,unhandled_type}).


parse_TypeWithConstraint([{'SEQUENCE',_},Lpar = {'(',_}|Rest]) ->
    {Constraint,Rest2} = parse_Constraint([Lpar|Rest]),
    Rest4 = case Rest2 of
		[{'OF',_}, {identifier,_,_Id}|Rest3] ->
%%% TODO: make some use of the identifier, maybe useful in the XML mapping
		    Rest3;
		[{'OF',_}|Rest3] ->
		    Rest3;
		_ ->
		    throw({asn1_error,
			   {get_line(hd(Rest2)),get(asn1_module),
			    [got,get_token(hd(Rest2)),expected,'OF']}})
	    end,
    {Type,Rest5} = parse_Type(Rest4),
    {#type{def = {'SEQUENCE OF',Type},
	   constraint = merge_constraints([Constraint])},Rest5};

parse_TypeWithConstraint([{'SEQUENCE',_},{'SIZE',_},Lpar = {'(',_}|Rest]) ->
    {Constraint,Rest2} = parse_Constraint([Lpar|Rest]),
    #constraint{c=C} = Constraint,
    Constraint2 = Constraint#constraint{c={element_set,{'SizeConstraint',C},
					   none}},
    Rest4 = case Rest2 of
		[{'OF',_}, {identifier,_,_Id}|Rest3] ->
%%% TODO: make some use of the identifier, maybe useful in the XML mapping
		    Rest3;
		[{'OF',_}|Rest3] ->
		    Rest3;
		_ ->
		    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
				       [got,get_token(hd(Rest2)),expected,'OF']}})
	    end,
    {Type,Rest5} = parse_Type(Rest4),
    {#type{def = {'SEQUENCE OF',Type}, constraint = merge_constraints([Constraint2])},Rest5};

parse_TypeWithConstraint([{'SET',_},Lpar = {'(',_}|Rest]) ->
    {Constraint,Rest2} = parse_Constraint([Lpar|Rest]),
    Rest4 = case Rest2 of
		[{'OF',_}, {identifier,_,_Id}|Rest3] ->
%%% TODO: make some use of the identifier, maybe useful in the XML mapping
		    Rest3;
		[{'OF',_}|Rest3] ->
		    Rest3;
		_ ->
		    throw({asn1_error,
			   {get_line(hd(Rest2)),get(asn1_module),
			    [got,get_token(hd(Rest2)),expected,'OF']}})
	    end,
    {Type,Rest5} = parse_Type(Rest4),
    {#type{def = {'SET OF',Type},
	   constraint = merge_constraints([Constraint])},Rest5};

parse_TypeWithConstraint([{'SET',_},{'SIZE',_},Lpar = {'(',_}|Rest]) ->
    {Constraint,Rest2} = parse_Constraint([Lpar|Rest]),
    #constraint{c=C} = Constraint,
    Constraint2 = Constraint#constraint{c={element_set,
					   {'SizeConstraint',C},none}},
    Rest4 = case Rest2 of
		[{'OF',_}, {identifier,_,_Id}|Rest3] ->
%%% TODO: make some use of the identifier, maybe useful in the XML mapping
		    Rest3;
		[{'OF',_}|Rest3] ->
		    Rest3;
		_ ->
		    throw({asn1_error,
			   {get_line(hd(Rest2)),get(asn1_module),
			    [got,get_token(hd(Rest2)),expected,'OF']}})
	    end,
    {Type,Rest5} = parse_Type(Rest4),
    {#type{def = {'SET OF',Type},
	   constraint = merge_constraints([Constraint2])},Rest5};

parse_TypeWithConstraint(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
		       ['SEQUENCE','SEQUENCE SIZE','SET','SET SIZE'],
		       followed,by,a,constraint]}}).


%% --------------------------

parse_ReferencedType(Tokens) ->
    Flist = [fun parse_DefinedType/1,
	     fun parse_SelectionType/1,
	     fun parse_TypeFromObject/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.
    
parse_DefinedType(Tokens=[{typereference,_,_},{'{',_}|_Rest]) ->
    parse_ParameterizedType(Tokens);
parse_DefinedType(Tokens=[{typereference,L1,TypeName},
			  T2={typereference,_,_},T3={'{',_}|Rest]) ->
    case (catch parse_ParameterizedType(Tokens)) of
	{'EXIT',_Reason} ->
	    Rest2 = [T2,T3|Rest],
	    {#type{def = #'Externaltypereference'{pos=L1,
						  module=resolve_module(TypeName),
						  type=TypeName}},Rest2};
	{asn1_error,_} ->
	    Rest2 = [T2,T3|Rest],
	    {#type{def = #'Externaltypereference'{pos=L1,
						  module=resolve_module(TypeName),
						  type=TypeName}},Rest2};
	Result ->
	    Result
    end;
parse_DefinedType(Tokens=[{typereference,_L1,_Module},{'.',_},
			  {typereference,_,_TypeName},{'{',_}|_Rest]) ->
    parse_ParameterizedType(Tokens);
parse_DefinedType([{typereference,L1,Module},{'.',_},{typereference,_,TypeName}|Rest]) ->
    {#type{def = #'Externaltypereference'{pos=L1,module=Module,type=TypeName}},Rest};
parse_DefinedType([{typereference,L1,TypeName}|Rest]) ->
    {#type{def = #'Externaltypereference'{pos=L1,module=resolve_module(TypeName),
					  type=TypeName}},Rest};
parse_DefinedType(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[typereference,'typereference.typereference',
			 'typereference typereference']]}}).

parse_SelectionType([{identifier,_,Name},{'<',_}|Rest]) ->    
    {Type,Rest2} = parse_Type(Rest),
    {{'SelectionType',Name,Type},Rest2};
parse_SelectionType(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'identifier <']}}).
    

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.

%% --------------------------


%% This should probably be removed very soon 
% parse_ConstrainedType(Tokens) ->
%     case (catch parse_TypeWithConstraint(Tokens)) of
% 	{'EXIT',Reason} ->
% 	    {Type,Rest} = parse_Type(Tokens),
% 	    {Constraint,Rest2} = parse_Constraint(Rest),
% 	    {Type#type{constraint=Constraint},Rest2};
% 	{asn1_error,Reason2} ->
% 	    {Type,Rest} = parse_Type(Tokens),
% 	    {Constraint,Rest2} = parse_Constraint(Rest),
% 	    {Type#type{constraint=Constraint},Rest2};
% 	Result ->
% 	    Result
%     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([Constraint|Acc]),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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,')']}})
    end;
parse_Constraint(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'(']}}).

parse_ConstraintSpec(Tokens) ->
    Flist = [fun parse_GeneralConstraint/1,
	     fun parse_SubtypeConstraint/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	{asn1_error,Reason2} ->
	    throw({asn1_error,Reason2});
	Result ->
	    Result
    end.

parse_ExceptionSpec([LPar={')',_}|Rest]) ->
    {undefined,[LPar|Rest]};
parse_ExceptionSpec([{'!',_}|Rest]) ->
    parse_ExceptionIdentification(Rest);
parse_ExceptionSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,[')','!']]}}).

parse_ExceptionIdentification(Tokens) ->
    Flist = [fun parse_SignedNumber/1,
	     fun parse_DefinedValue/1,
	     fun parse_TypeColonValue/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	{asn1_error,Reason2} ->
	    throw({asn1_error,Reason2});
	Result ->
	    Result
    end.

parse_TypeColonValue(Tokens) ->
    {Type,Rest} = parse_Type(Tokens),
    case Rest of
	[{':',_}|Rest2] ->
	    {Value,Rest3} = parse_Value(Rest2),
	    {{Type,Value},Rest3};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,':']}})
    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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,')']}})
    end;
parse_Elements(Tokens) ->
    Flist = [fun parse_ObjectSetElements/1,
	     fun parse_SubtypeElements/1,
%	     fun parse_Value/1,
%	     fun parse_Type/1,
	     fun parse_Object/1,
	     fun parse_DefinedObjectSet/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	Err = {asn1_error,_} ->
	    throw(Err);
	Result = {Val,_} when is_record(Val,type) ->
	    Result;

	Result ->
	    Result
    end.
    

    

%% --------------------------

parse_DefinedObjectClass([{typereference,_,_ModName},{'.',_},Tr={typereference,_,_ObjClName}|Rest]) ->
%%    {{objectclassname,ModName,ObjClName},Rest};
%    {{objectclassname,tref2Exttref(Tr)},Rest};
    {tref2Exttref(Tr),Rest};
parse_DefinedObjectClass([Tr={typereference,_,_ObjClName}|Rest]) ->
%    {{objectclassname,tref2Exttref(Tr)},Rest};
    {tref2Exttref(Tr),Rest};
parse_DefinedObjectClass(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			['typereference . typereference',
			 typereference,
			 'TYPE-IDENTIFIER',
			 'ABSTRACT-SYNTAX']]}}).

parse_ObjectClassAssignment([{typereference,L1,ObjClName},{'::=',_}|Rest]) ->
    {Type,Rest2} = parse_ObjectClass(Rest),
    {#classdef{pos=L1,name=ObjClName,module=resolve_module(Type),
	       typespec=Type},Rest2};
parse_ObjectClassAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   'typereference ::=']}}).

parse_ObjectClass(Tokens) ->
    Flist = [fun parse_DefinedObjectClass/1,
	     fun parse_ObjectClassDefn/1,
	     fun parse_ParameterizedObjectClass/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	{asn1_error,Reason2} ->
	    throw({asn1_error,Reason2});
	Result ->
	    Result
    end.

parse_ObjectClassDefn([{'CLASS',_},{'{',_}|Rest]) ->
    {Type,Rest2} = parse_FieldSpec(Rest),
    {WithSyntaxSpec,Rest3} = parse_WithSyntaxSpec(Rest2),
    {#objectclass{fields=Type,syntax=WithSyntaxSpec},Rest3};
parse_ObjectClassDefn(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'CLASS {']}}).

parse_FieldSpec(Tokens) ->
    parse_FieldSpec(Tokens,[]).

parse_FieldSpec(Tokens,Acc) ->
    Flist = [fun parse_FixedTypeValueFieldSpec/1,
	     fun parse_VariableTypeValueFieldSpec/1,
	     fun parse_ObjectFieldSpec/1,
	     fun parse_FixedTypeValueSetFieldSpec/1,
	     fun parse_VariableTypeValueSetFieldSpec/1,
	     fun parse_TypeFieldSpec/1,
	     fun parse_ObjectSetFieldSpec/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	{Type,[{'}',_}|Rest]} ->
	    {lists:reverse([Type|Acc]),Rest};
	{Type,[{',',_}|Rest2]} ->
	    parse_FieldSpec(Rest2,[Type|Acc]);
	{_,[H|_T]}  ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'}']}})
    end.

parse_PrimitiveFieldName([{typefieldreference,_,FieldName}|Rest]) ->
    {{typefieldreference,FieldName},Rest};
parse_PrimitiveFieldName([{valuefieldreference,_,FieldName}|Rest]) ->
    {{valuefieldreference,FieldName},Rest};
parse_PrimitiveFieldName(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[typefieldreference,valuefieldreference]]}}).

parse_FieldName(Tokens) ->
    {Field,Rest} = parse_PrimitiveFieldName(Tokens),
    parse_FieldName(Rest,[Field]).

parse_FieldName([{'.',_}|Rest],Acc) ->
    case (catch parse_PrimitiveFieldName(Rest)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	{FieldName,Rest2} ->
	    parse_FieldName(Rest2,[FieldName|Acc])
    end;
parse_FieldName(Tokens,Acc) ->
    {lists:reverse(Acc),Tokens}.
    
parse_FixedTypeValueFieldSpec([{valuefieldreference,L1,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 {Unique,Rest5} of
	{'UNIQUE',[{Del,_}|_]} when Del =:= ','; Del =:= '}' ->
	    {{fixedtypevaluefield,VFieldName,Type,Unique,
	      OptionalitySpec},Rest5};
	{_,[{Del,_}|_]} when Del =:= ','; Del =:= '}'  ->
	    {{object_or_fixedtypevalue_field,VFieldName,Type,Unique,OptionalitySpec},Rest5};
	_ ->
	    throw({asn1_error,{L1,get(asn1_module),
			       [got,get_token(hd(Rest5)),expected,[',','}']]}})
    end;
parse_FixedTypeValueFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,valuefieldreference]}}).

parse_VariableTypeValueFieldSpec([{valuefieldreference,L,VFieldName}|Rest]) ->
    {FieldRef,Rest2} = parse_FieldName(Rest),
    {OptionalitySpec,Rest3} = parse_ValueOptionalitySpec(Rest2),
    case Rest3 of
	[{Del,_}|_] when Del =:= ','; Del =:= '}' ->
	    {{variabletypevaluefield,VFieldName,FieldRef,OptionalitySpec},Rest3};
	_ ->
	    throw({asn1_error,{L,get(asn1_module),
			   [got,get_token(hd(Rest3)),expected,[',','}']]}})
    end;
parse_VariableTypeValueFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,valuefieldreference]}}).

parse_ObjectFieldSpec([{valuefieldreference,L,VFieldName}|Rest]) ->
    {Class,Rest2} = parse_DefinedObjectClass(Rest),
    {OptionalitySpec,Rest3} = parse_ObjectOptionalitySpec(Rest2),
    case Rest3 of
	[{Del,_}|_] when Del =:= ','; Del =:= '}' ->
	    {{objectfield,VFieldName,Class,undefined,OptionalitySpec},Rest3};
	_ ->
	    throw({asn1_error,{L,get(asn1_module),
			   [got,get_token(hd(Rest3)),expected,[',','}']]}})
    end;
parse_ObjectFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,valuefieldreference]}}).

parse_TypeFieldSpec([{typefieldreference,L,TFieldName}|Rest]) ->
    {OptionalitySpec,Rest2} = parse_TypeOptionalitySpec(Rest),
    case Rest2 of
	[{Del,_}|_] when Del =:= ','; Del =:= '}' ->
	    {{typefield,TFieldName,OptionalitySpec},Rest2};
	_ ->
	    throw({asn1_error,{L,get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,[',','}']]}})
    end;
parse_TypeFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,typefieldreference]}}).

parse_FixedTypeValueSetFieldSpec([{typefieldreference,L,TFieldName}|Rest]) ->
    {Type,Rest2} = parse_Type(Rest),
    {OptionalitySpec,Rest3} = parse_ValueSetOptionalitySpec(Rest2),
    case Rest3 of
	[{Del,_}|_] when Del =:= ','; Del =:= '}' ->
	    {{objectset_or_fixedtypevalueset_field,TFieldName,Type,
	      OptionalitySpec},Rest3};
	_ ->
	    throw({asn1_error,{L,get(asn1_module),
			       [got,get_token(hd(Rest3)),expected,[',','}']]}})
    end;  
parse_FixedTypeValueSetFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,typefieldreference]}}).

parse_VariableTypeValueSetFieldSpec([{typefieldreference,L,TFieldName}|Rest]) ->
    {FieldRef,Rest2} = parse_FieldName(Rest),
    {OptionalitySpec,Rest3} = parse_ValueSetOptionalitySpec(Rest2),
    case Rest3 of
	[{Del,_}|_] when Del =:= ','; Del =:= '}' ->
	    {{variabletypevaluesetfield,TFieldName,FieldRef,OptionalitySpec},Rest3};
	_ ->
	    throw({asn1_error,{L,get(asn1_module),
			       [got,get_token(hd(Rest3)),expected,[',','}']]}})
    end; 
parse_VariableTypeValueSetFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,typefieldreference]}}).

parse_ObjectSetFieldSpec([{typefieldreference,L,TFieldName}|Rest]) ->
    {Class,Rest2} = parse_DefinedObjectClass(Rest),
    {OptionalitySpec,Rest3} = parse_ObjectSetOptionalitySpec(Rest2),
    case Rest3 of
	[{Del,_}|_] when Del =:= ','; Del =:= '}' ->
	    {{objectsetfield,TFieldName,Class,OptionalitySpec},Rest3};
	_ ->
	    throw({asn1_error,{L,get(asn1_module),
			       [got,get_token(hd(Rest3)),expected,[',','}']]}})
    end;  
parse_ObjectSetFieldSpec(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,typefieldreference]}}).

parse_ValueOptionalitySpec(Tokens)->
    case Tokens of
	[{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest};
	[{'DEFAULT',_}|Rest] ->
	    {Value,Rest2} = parse_Value(Rest),
	    {{'DEFAULT',Value},Rest2};
	_  -> {'MANDATORY',Tokens}
    end.

parse_ObjectOptionalitySpec(Tokens) ->
    case Tokens of
	[{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest};
	[{'DEFAULT',_}|Rest] ->
	    {Object,Rest2} = parse_Object(Rest),
	    {{'DEFAULT',Object},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_ObjectSetOptionalitySpec(Tokens) ->
        case Tokens of
	[{'OPTIONAL',_}|Rest] -> {'OPTIONAL',Rest};
	[{'DEFAULT',_}|Rest] ->
	    {ObjectSet,Rest2} = parse_ObjectSet(Rest),
	    {{'DEFAULT',ObjectSet},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]) ->
    {[],Rest};
parse_SyntaxList([{'{',_}|Rest]) ->
    parse_SyntaxList(Rest,[]);
parse_SyntaxList(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,['{}','{']]}}).

parse_SyntaxList(Tokens,Acc) ->
    {SyntaxList,Rest} = parse_TokenOrGroupSpec(Tokens),
    case Rest of
	[{'}',_}|Rest2] -> 
	    {lists:reverse([SyntaxList|Acc]),Rest2};
	_ ->
	    parse_SyntaxList(Rest,[SyntaxList|Acc])
    end.

parse_TokenOrGroupSpec(Tokens) ->
    Flist = [fun parse_RequiredToken/1,
	     fun parse_OptionalGroup/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

parse_RequiredToken([{typereference,L1,WordName}|Rest]) ->
    case is_word(WordName) of
	false ->
	    throw({asn1_error,{L1,get(asn1_module),
			       [got,WordName,expected,a,'Word']}});
	true ->
	    {WordName,Rest}
    end;
parse_RequiredToken([{',',L1}|Rest]) ->
    {{',',L1},Rest};
parse_RequiredToken([{WordName,L1}|Rest]) ->
    case is_word(WordName) of
	false ->
	    throw({asn1_error,{L1,get(asn1_module),
			       [got,WordName,expected,a,'Word']}});
	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([{']',_}|Rest],Acc) ->
    {lists:reverse(Acc),Rest};
parse_OptionalGroup(Tokens,Acc) ->
    {Spec,Rest} = parse_TokenOrGroupSpec(Tokens),
    parse_OptionalGroup(Rest,[Spec|Acc]).

parse_DefinedObject([Id={identifier,_,_ObjName}|Rest]) ->
    {{object,identifier2Extvalueref(Id)},Rest};
parse_DefinedObject([{typereference,L1,ModName},{'.',_},{identifier,_,ObjName}|Rest]) ->
    {{object, #'Externaltypereference'{pos=L1,module=ModName,type=ObjName}},Rest};
parse_DefinedObject(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
		       [identifier,'typereference.identifier']]}}).

parse_ObjectAssignment([{identifier,L1,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};
	[H|_T]  -> 
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}});
	Other ->
	    throw({asn1_error,{L1,get(asn1_module),
			       [got,Other,expected,'::=']}})
    end;
parse_ObjectAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,identifier]}}).


%% parse_Object(Tokens) -> Ret
%% Tokens    = [Tok]
%% Tok       = tuple()
%% Ret       = {object,_} | {object, _, _}
parse_Object(Tokens) ->
    Flist=[fun parse_ObjectDefn/1,
	   fun parse_ObjectFromObject/1,
	   fun parse_ParameterizedObject/1,
	   fun parse_DefinedObject/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

parse_ObjectDefn(Tokens) ->
    Flist=[fun parse_DefaultSyntax/1,
	   fun parse_DefinedSyntax/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

parse_DefaultSyntax([{'{',_},{'}',_}|Rest]) ->
    {{object,defaultsyntax,[]},Rest};
parse_DefaultSyntax([{'{',_}|Rest]) ->
    parse_DefaultSyntax(Rest,[]);
parse_DefaultSyntax(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,['{}','{']]}}).

parse_DefaultSyntax(Tokens,Acc) ->
    {Setting,Rest} = parse_FieldSetting(Tokens),
    case Rest of
	[{',',_}|Rest2] ->
	    parse_DefaultSyntax(Rest2,[Setting|Acc]);
	[{'}',_}|Rest3] ->
	    {{object,defaultsyntax,lists:reverse([Setting|Acc])},Rest3};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,[',','}']]}})
    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,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([{',',L1}|Rest]) ->
    {{',',L1},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(Tokens=[{typereference,L1,_Name},{T,_}|_Rest]) 
  when T == '.'; T == '(' ->
    case catch parse_Setting(Tokens) of
	{asn1_error,_} ->
	    throw({asn1_error,{L1,get(asn1_module),
			       [got,hd(Tokens), expected,['Word',setting]]}});
	{'EXIT',Reason} ->
	    exit(Reason);
	Result ->
	    Result
    end;
parse_DefinedSyntaxToken(Tokens=[TRef={typereference,L1,Name}|Rest]) ->
    case is_word(Name) of
	false ->
	    case lookahead_definedsyntax(Rest) of
		word_or_setting ->
		    {{setting,L1,tref2Exttref(TRef)},Rest};
		_ ->
		    parse_Setting(Tokens)
	    end;
	true ->
	    %% {{word_or_setting,L1,Name},Rest}
	    {{word_or_setting,L1,tref2Exttref(TRef)},Rest}
    end;
parse_DefinedSyntaxToken(Tokens) ->
    case catch parse_Setting(Tokens) of
	{asn1_error,_} ->
	    parse_Word(Tokens);
	{'EXIT',Reason} ->
	    exit(Reason);
	Result ->
	    Result
    end.

lookahead_definedsyntax([{typereference,_,Name}|_Rest]) ->
    case is_word(Name)  of
	true -> word_or_setting;
	_ -> setting
    end;
lookahead_definedsyntax([{'}',_}|_Rest]) ->
    word_or_setting;
lookahead_definedsyntax(_) ->
    setting.
	    
parse_Word([{Name,Pos}|Rest]) ->
    case is_word(Name) of
	false ->
	    throw({asn1_error,{Pos,get(asn1_module),
			       [got,Name, expected,a,'Word']}});
	true ->
	    {{word_or_setting,Pos,tref2Exttref(Pos,Name)},Rest}
    end.

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 (catch parse_or_tag(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result = {{value_tag,_},_} ->
	    Result;
	{{Tag,Setting},Rest} when is_atom(Tag) ->
	    {Setting,Rest}
    end.

%% parse_Setting(Tokens) ->
%%     Flist = [fun parse_Type/1,
%% 	     fun parse_Value/1,
%% 	     fun parse_Object/1,
%% 	     fun parse_ObjectSet/1],
%%     case (catch parse_or(Tokens,Flist)) of
%% 	{'EXIT',Reason} ->
%% 	    exit(Reason);
%% 	AsnErr = {asn1_error,_} ->
%% 	    throw(AsnErr);
%% 	Result ->
%% 	    Result
%%     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) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[typereference,'typereference.typereference']]}}).

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};
	[H|_T]  -> 
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
%%%	Other ->
%%%	    throw(Other)
    end;
parse_ObjectSetAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   typereference]}}).

%% 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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'}']}})
    end;
parse_ObjectSet(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

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

% moved fun parse_Object/1 and fun parse_DefinedObjectSet/1 to parse_Elements
%% 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_Object/1,
	     %fun parse_DefinedObjectSet/1,
	     fun parse_ObjectSetFromObjects/1,
	     fun parse_ParameterizedObjectSet/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'.']}})
%%%	Other ->
%%%	    throw(Other)
    end.

%parse_ObjectClassFieldValue(Tokens) ->
%    Flist = [fun parse_OpenTypeFieldVal/1,
%	     fun parse_FixedTypeFieldVal/1],
%    case (catch parse_or(Tokens,Flist)) of
%	{'EXIT',Reason} ->
%	    throw(Reason);
%	AsnErr = {asn1_error,_} ->
%	    throw(AsnErr);
%	Result ->
%	    Result
%    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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,':']}})
    end.

% parse_FixedTypeFieldVal(Tokens) ->
%     parse_Value(Tokens).

% parse_InformationFromObjects(Tokens) ->
%     Flist = [fun parse_ValueFromObject/1,
% 	     fun parse_ValueSetFromObjects/1,
% 	     fun parse_TypeFromObject/1,
% 	     fun parse_ObjectFromObject/1],
%     case (catch parse_or(Tokens,Flist)) of
% 	{'EXIT',Reason} ->
% 	    throw(Reason);
% 	AsnErr = {asn1_error,_} ->
% 	    throw(AsnErr);
% 	Result ->
% 	    Result
%     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_ParameterizedObject/1,
	     fun parse_ParameterizedObjectSet/1],
        case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

parse_ValueFromObject(Tokens) ->
    {Objects,Rest} = parse_ReferencedObjects(Tokens),
    case Rest of
	[{'.',_}|Rest2] ->
	    {Name,Rest3} = parse_FieldName(Rest2),
	    case lists:last(Name) of
		{valuefieldreference,_} ->
		    {{'ValueFromObject',Objects,Name},Rest3};
		_ ->
		    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
				       [got,typefieldreference,expected,
					valuefieldreference]}})
	    end;
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'.']}})
%%%	Other ->
%%%	    throw({asn1_error,{got,Other,expected,'.'}})
    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} ->
		    {{'TypeFromObject',Objects,Name},Rest3};
		_ ->
		    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
				       [got,get_token(hd(Rest2)),expected,
					typefieldreference]}})
	    end;
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'.']}})
%%%	Other ->
%%%	    throw({asn1_error,{got,Other,expected,'.'}})
    end.

parse_ObjectFromObject(Tokens) ->
    {Objects,Rest} = parse_ReferencedObjects(Tokens),
    case Rest of
	[{'.',_}|Rest2] ->
	    {Name,Rest3} = parse_FieldName(Rest2),
	    {{'ObjectFromObject',Objects,Name},Rest3};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'.']}})
    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};
		_ ->
		    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
				       [got,get_token(hd(Rest2)),expected,
					typefieldreference]}})
	    end;
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'.']}})
    end.

% parse_InstanceOfType([{'INSTANCE',_},{'OF',_}|Rest]) ->
%     {Class,Rest2} = parse_DefinedObjectClass(Rest),
%     {{'InstanceOfType',Class},Rest2}.

% parse_InstanceOfValue(Tokens) ->
%     parse_Value(Tokens).



%% X.682 constraint specification

parse_GeneralConstraint(Tokens) ->
    Flist = [fun parse_UserDefinedConstraint/1,
	     fun parse_TableConstraint/1,
	     fun parse_ContentsConstraint/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'}']}})
    end;
parse_UserDefinedConstraint(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			['CONSTRAINED BY {}','CONSTRAINED BY {']]}}).

parse_UserDefinedConstraintParameter(Tokens) ->
    parse_UserDefinedConstraintParameter(Tokens,[]).
parse_UserDefinedConstraintParameter(Tokens,Acc) ->
    Flist = [fun parse_GovernorAndActualParameter/1,
	     fun parse_ActualParameter/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	{Result,Rest} ->
	    case Rest of
		[{',',_}|_Rest2] ->
		    parse_UserDefinedConstraintParameter(Tokens,[Result|Acc]);
		_  ->
		    {lists:reverse([Result|Acc]),Rest}
	    end
    end.

parse_GovernorAndActualParameter(Tokens) ->
    {Governor,Rest} = parse_Governor(Tokens),
    case Rest of
	[{':',_}|Rest2] ->
	    {Params,Rest3} = parse_ActualParameter(Rest2),
	    {{'Governor_Params',Governor,Params},Rest3};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,':']}})
    end.

parse_TableConstraint(Tokens) ->
    Flist = [fun parse_ComponentRelationConstraint/1,
	     fun parse_SimpleTableConstraint/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

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};
		[H|_T]  ->
		    throw({asn1_error,{get_line(H),get(asn1_module),
				       [got,get_token(H),expected,'}']}})
	    end;
	[H|_T]  ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,
				'ComponentRelationConstraint',ended,with,'}']}})
%%%	Other ->
%%%	    throw(Other)
    end;
parse_ComponentRelationConstraint(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

parse_AtNotationList(Tokens,Acc) ->
    {AtNot,Rest} = parse_AtNotation(Tokens),
    case Rest of
	[{',',_}|Rest2] ->
	    parse_AtNotationList(Rest2,[AtNot|Acc]);
	_  ->
	    {lists:reverse([AtNot|Acc]),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) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,['@','@.']]}}).

parse_ComponentIdList(Tokens) ->
    parse_ComponentIdList(Tokens,[]).

parse_ComponentIdList([Id = {identifier,_,_},{'.',_}|Rest],Acc) ->
    parse_ComponentIdList(Rest,[identifier2Extvalueref(Id)|Acc]);
parse_ComponentIdList([Id = {identifier,_,_}|Rest],Acc) ->
    {lists:reverse([identifier2Extvalueref(Id)|Acc]),Rest};
parse_ComponentIdList(Tokens,_) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[identifier,'identifier.']]}}).

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) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			'CONTAINING','or','ENCODED BY']}}).


% X.683 Parameterization of ASN.1 specifications

parse_Governor(Tokens) ->
    Flist = [fun parse_Type/1,
	     fun parse_DefinedObjectClass/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

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],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

parse_ParameterizedAssignment(Tokens) ->
    Flist = [fun parse_ParameterizedTypeAssignment/1,
	     fun parse_ParameterizedValueAssignment/1,
	     fun parse_ParameterizedValueSetTypeAssignment/1,
	     fun parse_ParameterizedObjectClassAssignment/1,
	     fun parse_ParameterizedObjectAssignment/1,
	     fun parse_ParameterizedObjectSetAssignment/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	AsnAssErr = {asn1_assignment_error,_} ->
	    throw(AsnAssErr);
	Result ->
	    Result
    end.

%% 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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
    end;
parse_ParameterizedTypeAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   typereference]}}).

%% parse_ParameterizedValueAssignment(Tokens) -> Result
%% Result = {#pvaluedef{},Rest} | throw()
parse_ParameterizedValueAssignment([{identifier,L1,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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
    end;
parse_ParameterizedValueAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,identifier]}}).

%% 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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
    end;
parse_ParameterizedValueSetTypeAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   typereference]}}).

%% 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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
    end;
parse_ParameterizedObjectClassAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   typereference]}}).

%% parse_ParameterizedObjectAssignment(Tokens) -> Result
%% Result = {#pobjectdef{},Rest} | throw()
parse_ParameterizedObjectAssignment([{identifier,L1,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};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
%%%	Other ->
%%%	    throw(Other)
    end;
parse_ParameterizedObjectAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,identifier]}}).

%% parse_ParameterizedObjectSetAssignment(Tokens) -> Result
%% Result = {#pobjectsetdef{},Rest} | throw{}
parse_ParameterizedObjectSetAssignment([{typereference,L1,Name}|Rest]) ->
    {ParameterList,Rest2} = parse_ParameterList(Rest),
    {Class,Rest3} = parse_DefinedObjectClass(Rest2),
    case Rest3 of
	[{'::=',_}|Rest4] ->
	    {ObjectSet,Rest5} = parse_ObjectSet(Rest4),
	    {#pobjectsetdef{pos=L1,name=Name,args=ParameterList,
			    class=Class,def=ObjectSet},Rest5};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
%%%	Other ->
%%%	    throw(Other)
    end;
parse_ParameterizedObjectSetAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   typereference]}}).

%% parse_ParameterList(Tokens) -> Result
%% Result = [Parameter]
%% Parameter = {Governor,Reference} | Reference
%% Governor = Type | DefinedObjectClass
%% Type = #type{}
%% DefinedObjectClass = #'Externaltypereference'{}
%% Reference = #'Externaltypereference'{} | #'Externalvaluereference'{}
parse_ParameterList([{'{',_}|Rest]) ->
    parse_ParameterList(Rest,[]);
parse_ParameterList(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

parse_ParameterList(Tokens,Acc) ->
    {Parameter,Rest} = parse_Parameter(Tokens),
    case Rest of
	[{',',_}|Rest2] ->
	    parse_ParameterList(Rest2,[Parameter|Acc]);
	[{'}',_}|Rest3] ->
	    {lists:reverse([Parameter|Acc]),Rest3};
	[H|_T]  ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,[',','}']]}})
    end.

parse_Parameter(Tokens) ->
    Flist = [fun parse_ParamGovAndRef/1,
	     fun parse_Reference/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

parse_ParamGovAndRef(Tokens) ->
    {ParamGov,Rest} = parse_ParamGovernor(Tokens),
    case Rest of
	[{':',_}|Rest2] ->
	    {Ref,Rest3} = parse_Reference(Rest2),
	    {{ParamGov,Ref},Rest3};
	[H|_T] ->
	   throw({asn1_error,{get_line(H),get(asn1_module),
			      [got,get_token(H),expected,':']}})
    end.

parse_ParamGovernor(Tokens) ->
    Flist = [fun parse_Governor/1,
	     fun parse_Reference/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

% parse_ParameterizedReference(Tokens) ->
%     {Ref,Rest} = parse_Reference(Tokens),
%     case Rest of
% 	[{'{',_},{'}',_}|Rest2] ->
% 	    {{ptref,Ref},Rest2};
% 	_  ->
% 	    {{ptref,Ref},Rest}
%     end.

parse_SimpleDefinedType([{typereference,L1,ModuleName},{'.',_},
			 {typereference,_,TypeName}|Rest]) ->
    {#'Externaltypereference'{pos=L1,module=ModuleName,
						 type=TypeName},Rest};
parse_SimpleDefinedType([Tref={typereference,_,_}|Rest]) ->
%    {#'Externaltypereference'{pos=L2,module=get(asn1_module),
%						 type=TypeName},Rest};
    {tref2Exttref(Tref),Rest};
parse_SimpleDefinedType(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[typereference,'typereference.typereference']]}}).

parse_SimpleDefinedValue([{typereference,L1,ModuleName},{'.',_},
			  {identifier,_,Value}|Rest]) ->
    {{simpledefinedvalue,#'Externalvaluereference'{pos=L1,module=ModuleName,
						   value=Value}},Rest};
parse_SimpleDefinedValue([Id={identifier,_,_Value}|Rest]) ->
    {{simpledefinedvalue,identifier2Extvalueref(Id)},Rest};
parse_SimpleDefinedValue(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			['typereference.identifier',identifier]]}}).

parse_ParameterizedType(Tokens) ->
    {Type,Rest} = parse_SimpleDefinedType(Tokens),
    {Params,Rest2} = parse_ActualParameterList(Rest),
    {{pt,Type,Params},Rest2}.

parse_ParameterizedValue(Tokens) ->
    {Value,Rest} = parse_SimpleDefinedValue(Tokens),
    {Params,Rest2} = parse_ActualParameterList(Rest),
    {{pv,Value,Params},Rest2}.

parse_ParameterizedObjectClass(Tokens) ->
    {Type,Rest} = parse_DefinedObjectClass(Tokens),
    {Params,Rest2} = parse_ActualParameterList(Rest),
    {{poc,Type,Params},Rest2}.

parse_ParameterizedObjectSet(Tokens) ->
    {ObjectSet,Rest} = parse_DefinedObjectSet(Tokens),
    {Params,Rest2} = parse_ActualParameterList(Rest),
    {{pos,ObjectSet,Params},Rest2}.

parse_ParameterizedObject(Tokens) ->
    {Object,Rest} = parse_DefinedObject(Tokens),
    {Params,Rest2} = parse_ActualParameterList(Rest),
    {{po,Object,Params},Rest2}.

parse_ActualParameterList([{'{',_}|Rest]) ->
    parse_ActualParameterList(Rest,[]);
parse_ActualParameterList(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

parse_ActualParameterList(Tokens,Acc) ->
    {Parameter,Rest} = parse_ActualParameter(Tokens),
    case Rest of
	[{',',_}|Rest2] ->
	    parse_ActualParameterList(Rest2,[Parameter|Acc]);
	[{'}',_}|Rest3] ->
	    {lists:reverse([Parameter|Acc]),Rest3};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,[',','}']]}})
%%%	Other ->
%%%	    throw(Other)
    end.







%-------------------------

is_word(Token) ->
    case not_allowed_word(Token) of
	true -> false;
	_ ->
	    if
		is_atom(Token) ->
		    Item = atom_to_list(Token),
		    is_word(Item);
		is_list(Token), length(Token) == 1 ->
		    check_one_char_word(Token);
		is_list(Token) ->
		    [A|Rest] = Token,
		    case check_first(A) of
			true ->
			    check_rest(Rest);
			_ -> 
			    false
		    end
	    end
    end.

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_one_char_word([A]) when $A =< A, $Z >= A ->
    true;
check_one_char_word([_]) ->
    false. %% unknown item in SyntaxList

check_first(A) when $A =< A, $Z >= A ->
    true;
check_first(_) ->
    false. %% unknown item in SyntaxList

check_rest([R,R|_Rs]) when $- == R ->
    false; %% two consecutive hyphens are not allowed in a word
check_rest([R]) when $- == R ->
    false; %% word cannot end with hyphen
check_rest([R|Rs]) when $A=<R, $Z>=R; $-==R ->
    check_rest(Rs);
check_rest([]) ->
    true;
check_rest(_) ->
    false.

parse_AlternativeTypeLists(Tokens) ->
    parse_AlternativeTypeLists(Tokens,[]).

parse_AlternativeTypeLists(Tokens = [{identifier,_,_}|_Rest0],Clist) ->
    {CompList,Rest1} = parse_AlternativeTypeList(Tokens,[]),
    parse_AlternativeTypeLists(Rest1,Clist++CompList);
parse_AlternativeTypeLists([{'...',L1},{'!',_}|Rest02],Clist0) ->
    {_,Rest03} = parse_ExceptionIdentification(Rest02),
    %% Exception info is currently thrown away
    parse_AlternativeTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]);
parse_AlternativeTypeLists([{',',L1},{'...',_},{'!',_}|Rest02],Clist0) when Clist0 =/= []->
    {_,Rest03} = parse_ExceptionIdentification(Rest02),
    %% Exception info is currently thrown away
    parse_AlternativeTypeLists2(Rest03,Clist0++[#'EXTENSIONMARK'{pos=L1}]);

parse_AlternativeTypeLists([{',',_},{'...',L1}|Rest02],Clist0) when Clist0 =/= []->
    parse_AlternativeTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]);
parse_AlternativeTypeLists([{'...',L1}|Rest02],Clist0) ->
    parse_AlternativeTypeLists2(Rest02,Clist0++[#'EXTENSIONMARK'{pos=L1}]);
parse_AlternativeTypeLists(Tokens = [{'}',_L1}|_Rest02],Clist0) ->
    {Clist0,Tokens}.

parse_AlternativeTypeLists2(Tokens,Clist) ->
    {ExtAdd,Rest} = parse_ExtensionAdditionAlternatives(Tokens,Clist),
    {Clist2,Rest2} = parse_OptionalExtensionMarker(Rest,lists:flatten(ExtAdd)),
    case Rest2 of
	[{',',_}|Rest3] ->
	    {CompList,Rest4} = parse_AlternativeTypeList(Rest3,[]),
	    {Clist2 ++ CompList,Rest4};
	_ ->
	    {Clist2,Rest2}
    end.



parse_AlternativeTypeList([{',',_},Id = {identifier,_,_}|Rest],Acc) when Acc =/= [] ->
    {AlternativeType,Rest2} = parse_NamedType([Id|Rest]),
    parse_AlternativeTypeList(Rest2,[AlternativeType|Acc]);
parse_AlternativeTypeList(Tokens = [{'}',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_AlternativeTypeList(Tokens = [{']',_},{']',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_AlternativeTypeList(Tokens = [{',',_},{'...',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_AlternativeTypeList(Tokens,[]) ->
    {AlternativeType,Rest} = parse_NamedType(Tokens),
    parse_AlternativeTypeList(Rest,[AlternativeType]);
parse_AlternativeTypeList(Tokens,_) ->
    throw({asn1_error,
	   {get_line(hd(Tokens)),get(asn1_module),
	    [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))],
	     expected,['}',', identifier']]}}).

parse_ExtensionAdditionAlternatives(Tokens =[{',',_}|_],Clist) ->
    {ExtAddList,Rest2} = parse_ExtensionAdditionAlternativesList(Tokens,[]),
    {Clist++lists:flatten(ExtAddList),Rest2};
parse_ExtensionAdditionAlternatives(Tokens,Clist) ->
    %% Empty
    {Clist,Tokens}.

parse_ExtensionAdditionAlternativesList([{',',_},Id = {identifier,_,_}|Rest],Acc) ->
    {AlternativeType,Rest2} = parse_NamedType([Id|Rest]),
    parse_ExtensionAdditionAlternativesList(Rest2,[AlternativeType|Acc]);
parse_ExtensionAdditionAlternativesList([{',',_},C1 = {'[',_},C2 = {'[',_}|Rest],Acc) ->
    {ExtAddGroup,Rest2} = parse_ExtensionAdditionAlternativesGroup([C1,C2|Rest],[]),
    parse_ExtensionAdditionAlternativesList(Rest2,[ExtAddGroup|Acc]);
parse_ExtensionAdditionAlternativesList(Tokens = [{'}',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_ExtensionAdditionAlternativesList(Tokens = [{',',_},{'...',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_ExtensionAdditionAlternativesList(Tokens,_) ->
    throw({asn1_error,
	   {get_line(hd(Tokens)),get(asn1_module),
	    [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))],
	     expected,['}',', identifier']]}}).


parse_ExtensionAdditionAlternativesGroup([ {'[',_},{'[',_},_VsnNr = {number,_,Num},{':',_}|Rest],[]) ->
    parse_ExtensionAdditionAlternativesGroup2(Rest,Num);
parse_ExtensionAdditionAlternativesGroup([ {'[',_},{'[',_}|Rest],[]) ->
    parse_ExtensionAdditionAlternativesGroup2(Rest,undefined);
parse_ExtensionAdditionAlternativesGroup(Tokens,_) ->
    throw({asn1_error,
	   {get_line(hd(Tokens)),get(asn1_module),
	    [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))],
	     expected,['[[']]}}).


parse_ExtensionAdditionAlternativesGroup2(Tokens,Num) ->
    {CompTypeList,Rest} = parse_AlternativeTypeList(Tokens,[]),
    case Rest of
	[{']',_},{']',_}|Rest2] ->
	    {[{'ExtensionAdditionGroup',Num}|CompTypeList] ++
		['ExtensionAdditionGroupEnd'],Rest2};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest)),get(asn1_module),
			       [got,get_token(hd(Rest)),expected,[']]']]}})
    end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% parse_AlternativeTypeLists(Tokens,ExtensionDefault) ->
%%     {AltTypeList,Rest1} = parse_AlternativeTypeList(Tokens),
%%     {ExtensionAndException,Rest2} =
%% 	case Rest1 of
%% 	    [{',',_},{'...',L1},{'!',_}|Rest12] ->
%% 		{_,Rest13} = parse_ExceptionIdentification(Rest12),
%% 		%% Exception info is currently thrown away
%% 		{[#'EXTENSIONMARK'{pos=L1}],Rest13};
%% 	    [{',',_},{'...',L1}|Rest12] ->
%% 		{[#'EXTENSIONMARK'{pos=L1}],Rest12};
%% 	    _ ->
%% 		{[],Rest1}
%% 	end,
%%     {AltTypeList2,Rest5} =
%% 	case ExtensionAndException of
%% 	    [] ->
%% 		{AltTypeList,Rest2};
%% 	    _ ->
%% 		{ExtensionAddition,Rest3} =
%% 		    case Rest2 of
%% 			[{',',_}|Rest23] ->
%% 			    parse_ExtensionAdditionAlternativeList(Rest23);
%% 			_ ->
%% 			    {[],Rest2}
%% 		    end,
%% 		{OptionalExtensionMarker,Rest4} =
%% 		    case Rest3 of
%% 			[{',',_},{'...',L3}|Rest31] ->
%% 			    {[#'EXTENSIONMARK'{pos=L3}],Rest31};
%% 			_ ->
%% 			    {[],Rest3}
%% 		    end,
%% 		{AltTypeList ++ ExtensionAndException ++
%% 		 ExtensionAddition ++ OptionalExtensionMarker, Rest4}
%% 	end,
%%     AltTypeList3 =
%% 	case [X || X=#'EXTENSIONMARK'{} <- AltTypeList2] of
%% 	    [] when ExtensionDefault == 'IMPLIED' ->
%% 		AltTypeList2 ++ [#'EXTENSIONMARK'{}];
%% 	    _ ->
%% 		AltTypeList2
%% 	end,
%%     {AltTypeList3,Rest5}.
    

%% parse_AlternativeTypeList(Tokens) ->
%%     parse_AlternativeTypeList(Tokens,[]).

%% parse_AlternativeTypeList(Tokens,Acc) ->
%%     {NamedType,Rest} = parse_NamedType(Tokens),
%%     case Rest of
%% 	[{',',_},Id = {identifier,_,_}|Rest2] ->
%% 	    parse_AlternativeTypeList([Id|Rest2],[NamedType|Acc]);
%% 	_ ->
%% 	    {lists:reverse([NamedType|Acc]),Rest}
%%     end.

    

%% parse_ExtensionAdditionAlternativeList(Tokens) ->
%%     parse_ExtensionAdditionAlternativeList(Tokens,[]).

%% parse_ExtensionAdditionAlternativeList([{'[[',_}|Rest],Acc) ->
%%     parse_ExtensionAdditionAlternativeList(Rest,Acc);
%% parse_ExtensionAdditionAlternativeList(Tokens = [{identifier,_,_}|_Rest],Acc) ->
%%     {Element,Rest0} = parse_NamedType(Tokens);
%%     case Rest0 of
%% 	[{',',_}|Rest01] ->
%% 	    parse_ExtensionAdditionAlternativeList(Rest01,[Element|Acc]);
%% 	_  ->
%% 	    {lists:reverse([Element|Acc]),Rest0}
%%     end.

%% parse_ExtensionAdditionAlternatives([{'[[',_}|Rest]) ->
%%     parse_ExtensionAdditionAlternatives(Rest,[]);
%% parse_ExtensionAdditionAlternatives(Tokens) ->
%%     throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
%% 		       [got,get_token(hd(Tokens)),expected,'[[']}}).

%% parse_ExtensionAdditionAlternatives([Id = {identifier,_,_}|Rest],Acc) ->
%%     {NamedType, Rest2} = parse_NamedType([Id|Rest]),
%%     case Rest2 of
%% 	[{',',_}|Rest21] ->
%% 	    parse_ExtensionAdditionAlternatives(Rest21,[NamedType|Acc]);
%% 	[{']]',_}|Rest21] ->
%% 	    {lists:reverse(Acc),Rest21};
%% 	_ ->
%% 	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
%% 			       [got,get_token(hd(Rest2)),expected,[',',']]']]}})
%%     end.

parse_NamedType([{identifier,L1,Idname}|Rest]) ->
    {Type,Rest2} = parse_Type(Rest),
    {#'ComponentType'{pos=L1,name=Idname,typespec=Type,prop=mandatory},Rest2};
parse_NamedType(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,identifier]}}).


parse_ComponentTypeLists(Tokens) ->
    parse_ComponentTypeLists(Tokens,[]).

parse_ComponentTypeLists(Tokens = [{identifier,_,_}|_Rest0],Clist) ->
    {CompList,Rest1} = parse_ComponentTypeList(Tokens,[]),
    parse_ComponentTypeLists(Rest1,Clist++CompList);
parse_ComponentTypeLists(Tokens = [{'COMPONENTS',_},{'OF',_}|_Rest],Clist) ->
    {CompList,Rest1} = parse_ComponentTypeList(Tokens,[]),
    parse_ComponentTypeLists(Rest1,Clist++CompList);
parse_ComponentTypeLists([{'...',L1},{'!',_}|Rest02],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 =/= []->
    {_,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_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([{',',_},Id = {identifier,_,_}|Rest],Acc) when Acc =/= [] ->
    {ComponentType,Rest2} = parse_ComponentType([Id|Rest]),
    parse_ComponentTypeList(Rest2,[ComponentType|Acc]);
parse_ComponentTypeList([{',',_},C1={'COMPONENTS',_},C2={'OF',_}|Rest],Acc) when Acc =/= [] ->
    {ComponentType,Rest2} = parse_ComponentType([C1,C2|Rest]),
    parse_ComponentTypeList(Rest2,[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,_) ->
    throw({asn1_error,
	   {get_line(hd(Tokens)),get(asn1_module),
	    [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))],
	     expected,['}',', identifier']]}}).

parse_ExtensionAdditions(Tokens=[{',',_}|_],Clist) ->
    {ExtAddList,Rest2} = parse_ExtensionAdditionList(Tokens,[]),
    {Clist++ExtAddList,Rest2};
parse_ExtensionAdditions(Tokens,Clist) ->
    %% Empty
    {Clist,Tokens}.

parse_ExtensionAdditionList([{',',_},Id = {identifier,_,_}|Rest],Acc) ->
    {ComponentType,Rest2} = parse_ComponentType([Id|Rest]),
    parse_ExtensionAdditionList(Rest2,[ComponentType|Acc]);
parse_ExtensionAdditionList([{',',_},C1={'COMPONENTS',_},C2={'OF',_}|Rest],Acc) ->
    {ComponentType,Rest2} = parse_ComponentType([C1,C2|Rest]),
    parse_ExtensionAdditionList(Rest2,[ComponentType|Acc]);
parse_ExtensionAdditionList([{',',_},C1 = {'[',_},C2 = {'[',_}|Rest],Acc) ->
    {ExtAddGroup,Rest2} = parse_ExtensionAdditionGroup([C1,C2|Rest],[]),
    parse_ExtensionAdditionList(Rest2,[ExtAddGroup|Acc]);
parse_ExtensionAdditionList(Tokens = [{'}',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_ExtensionAdditionList(Tokens = [{',',_},{'...',_}|_],Acc) ->
    {lists:reverse(Acc),Tokens};
parse_ExtensionAdditionList(Tokens,_) ->
    throw({asn1_error,
	   {get_line(hd(Tokens)),get(asn1_module),
	    [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))],
	     expected,['}',', identifier']]}}).


parse_ExtensionAdditionGroup([ {'[',_},{'[',_},_VsnNr = {number,_,Num},{':',_}|Rest],[]) ->
    parse_ExtensionAdditionGroup2(Rest,Num);
parse_ExtensionAdditionGroup([ {'[',_},{'[',_}|Rest],[]) ->
    parse_ExtensionAdditionGroup2(Rest,undefined);
parse_ExtensionAdditionGroup(Tokens,_) ->
    throw({asn1_error,
	   {get_line(hd(Tokens)),get(asn1_module),
	    [got,[get_token(hd(Tokens)),get_token(hd(tl(Tokens)))],
	     expected,['[[']]}}).


parse_ExtensionAdditionGroup2(Tokens,Num) ->
    {CompTypeList,Rest} = parse_ComponentTypeList(Tokens,[]),
    case Rest of
	[{']',_},{']',_}|Rest2] ->
	    {[{'ExtensionAdditionGroup',Num}|CompTypeList] ++
		['ExtensionAdditionGroupEnd'],Rest2};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest)),get(asn1_module),
			       [got,get_token(hd(Rest)),expected,[']]']]}})
    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_SignedNumber([{number,_,Value}|Rest]) ->
    {Value,Rest};
parse_SignedNumber([{'-',_},{number,_,Value}|Rest]) ->
    {-Value,Rest};
parse_SignedNumber(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,
			[number,'-number']]}}).

parse_Enumerations(Tokens=[{identifier,_,_}|_Rest],ExtensionDefault) ->
    parse_Enumerations(Tokens,[],ExtensionDefault);
parse_Enumerations([H|_T],_) ->
    throw({asn1_error,{get_line(H),get(asn1_module),
		       [got,get_token(H),expected,identifier]}}).

parse_Enumerations(Tokens = [{identifier,_,_},{'(',_}|_Rest], Acc, ExtensionDefault) ->
    {NamedNumber,Rest2} = parse_NamedNumber(Tokens),
    case Rest2 of
	[{',',_}|Rest3] ->
	    parse_Enumerations(Rest3,[NamedNumber|Acc], ExtensionDefault);
	_ when ExtensionDefault == 'IMPLIED'->
	    {lists:reverse(['EXTENSIONMARK',NamedNumber|Acc]),Rest2};
	_ ->
	    {lists:reverse([NamedNumber|Acc]),Rest2}
    end;
parse_Enumerations([{identifier,_,Id}|Rest], Acc, ExtensionDefault) ->
    case Rest of
	[{',',_}|Rest2] ->
	    parse_Enumerations(Rest2,[Id|Acc], ExtensionDefault);
	_ when ExtensionDefault == 'IMPLIED' ->
	    {lists:reverse(['EXTENSIONMARK', Id |Acc]),Rest};
	_ ->
	    {lists:reverse([Id|Acc]),Rest}
    end;
parse_Enumerations([{'...',_}|Rest], Acc, _ExtensionDefault) ->
    case Rest of
	[{',',_}|Rest2] ->
	    parse_Enumerations(Rest2,['EXTENSIONMARK'|Acc],undefined);
	_ ->
	    {lists:reverse(['EXTENSIONMARK'|Acc]),Rest}
    end;
parse_Enumerations([H|_T],_,_) ->
    throw({asn1_error,{get_line(H),get(asn1_module),
		       [got,get_token(H),expected,identifier]}}).

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([NamedNum|Acc]),Rest}
    end.

parse_NamedNumber([{identifier,_,Name},{'(',_}|Rest]) ->
    Flist = [fun parse_SignedNumber/1,
	     fun parse_DefinedValue/1],
    case (catch parse_or(Rest,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	{NamedNum,[{')',_}|Rest2]} ->
	    {{'NamedNumber',Name,NamedNum},Rest2};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest)),get(asn1_module),
			       [got,get_token(hd(Rest)),expected,'NamedNumberList']}})
    end;
parse_NamedNumber(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,identifier]}}).


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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest3)),get(asn1_module),
			       [got,get_token(hd(Rest3)),expected,']']}})
    end;
parse_Tag(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'[']}}).

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],

    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end.

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],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	Result ->
	    Result
    end;
parse_BuiltinValue([{identifier,_,IdName},{':',_}|Rest]) ->
    {Value,Rest2} = parse_Value(Rest),
    {{'CHOICE',{IdName,Value}},Rest2};
parse_BuiltinValue(Tokens=[{'NULL',_},{':',_}|_Rest])  ->
    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([{'-',_},{number,_,Num}|Rest]) ->
    {- Num,Rest};
parse_BuiltinValue(Tokens) ->
    parse_ObjectClassFieldValue(Tokens).

parse_DefinedValue(Tokens=[{identifier,_,_},{'{',_}|_Rest]) ->
    parse_ParameterizedValue(Tokens);
%% Externalvaluereference
parse_DefinedValue([{typereference,L1,Tname},{'.',_},{identifier,_,Idname}|Rest]) ->
    {#'Externalvaluereference'{pos=L1,module=Tname,value=Idname},Rest};
%% valuereference
parse_DefinedValue([Id = {identifier,_,_}|Rest]) ->
    {identifier2Extvalueref(Id),Rest};
%% ParameterizedValue
parse_DefinedValue(Tokens) ->
    parse_ParameterizedValue(Tokens).


parse_SequenceValue([{'{',_}|Tokens]) ->
    parse_SequenceValue(Tokens,[]);
parse_SequenceValue(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

parse_SequenceValue([{identifier,Pos,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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    end;
parse_SequenceValue(Tokens,_Acc) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,identifier]}}).

parse_SequenceOfValue([{'{',_}|Tokens]) ->
    parse_SequenceOfValue(Tokens,[]);
parse_SequenceOfValue(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

parse_SequenceOfValue(Tokens,Acc) ->
    {Value,Rest2} = parse_Value(Tokens),
    case Rest2 of
	[{',',_}|Rest3] ->
	    parse_SequenceOfValue(Rest3,[Value|Acc]);
	[{'}',_}|Rest3] ->
	    {lists:reverse([Value|Acc]),Rest3};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'}']}})
    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};
	[H|_T] ->
	    throw({asn1_error,{get_line(L1),get(asn1_module),
			       [got,get_token(H),expected,'::=']}})
    end;
parse_ValueSetTypeAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,
				   typereference]}}).

parse_ValueSet([{'{',_}|Rest]) ->
    {Elems,Rest2} = parse_ElementSetSpecs(Rest),
    case Rest2 of
	[{'}',_}|Rest3] ->
	    {{valueset,Elems},Rest3};
	[H|_T] ->
	    throw({asn1_error,{get_line(H),get(asn1_module),
			       [got,get_token(H),expected,'}']}})
    end;
parse_ValueSet(Tokens) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'{']}}).

parse_ValueAssignment([{identifier,L1,IdName}|Rest]) ->
    {Type,Rest2} = parse_Type(Rest),
    case Rest2 of
	[{'::=',_}|Rest3] ->
	    {Value,Rest4} = parse_Value(Rest3),
	    case catch lookahead_assignment(Rest4) of
		ok ->
		    {#valuedef{pos=L1,name=IdName,type=Type,value=Value,
			       module=get(asn1_module)},Rest4};
		Error ->
		    throw(Error)
%% 		    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
%% 				       [got,get_token(hd(Rest2)),expected,'::=']}})
	    end;
	_ ->
	    throw({asn1_error,{get_line(hd(Rest2)),get(asn1_module),
			       [got,get_token(hd(Rest2)),expected,'::=']}})
    end;
parse_ValueAssignment(Tokens) ->
    throw({asn1_assignment_error,{get_line(hd(Tokens)),get(asn1_module),
				  [got,get_token(hd(Tokens)),expected,identifier]}}).

%% 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};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest)),get(asn1_module),
			       [got,get_token(hd(Rest)),expected,'}']}})
    end;
parse_SubtypeElements([{'WITH',_},{'COMPONENTS',_},{'{',_}|Tokens]) ->
    {Constraint,Rest} = parse_TypeConstraints(Tokens),
    case Rest of
	[{'}',_}|Rest2] ->
	    {{'WITH COMPONENTS',{'FullSpecification',Constraint}},Rest2};
	_ ->
	    throw({asn1_error,{get_line(hd(Rest)),get(asn1_module),
			       [got,get_token(hd(Rest)),expected,'}']}})
    end;
parse_SubtypeElements([{'PATTERN',_}|Tokens]) ->
    {Value,Rest} = parse_Value(Tokens),
    {{pattern,Value},Rest};
%% SingleValue
%% ContainedSubtype
%% ValueRange
%% TypeConstraint
%% Moved fun parse_Value/1 and fun parse_Type/1 to parse_Elements
parse_SubtypeElements(Tokens) ->
    Flist = [fun parse_ContainedSubtype/1,
	     fun parse_Value/1, 
	     fun([{'MIN',_}|T]) -> {'MIN',T} end,
	     fun parse_Type/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	{asn1_error,Reason} ->
	    throw(Reason);
	Result = {Val,_} when is_record(Val,type) ->
	    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) ->
    throw({asn1_error,{get_line(hd(Tokens)),get(asn1_module),
		       [got,get_token(hd(Tokens)),expected,'INCLUDES']}}).
%%parse_ContainedSubtype(Tokens) -> %this option is moved to parse_SubtypeElements
%%    parse_Type(Tokens).

parse_UpperEndpoint([{'<',_}|Rest]) ->
    parse_UpperEndpoint(lt,Rest);
parse_UpperEndpoint(Tokens) ->
    parse_UpperEndpoint(false,Tokens).

parse_UpperEndpoint(Lt,Tokens) ->
    Flist = [ fun([{'MAX',_}|T]) -> {'MAX',T} end,
	      fun parse_Value/1],
    case (catch parse_or(Tokens,Flist)) of
	{'EXIT',Reason} ->
	    exit(Reason);
	AsnErr = {asn1_error,_} ->
	    throw(AsnErr);
	{Value,Rest2} when Lt == lt ->
	    {{lt,Value},Rest2};
	{Value,Rest2} ->
	    {Value,Rest2}
    end.

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([ComponentConstraint|Acc]),Rest2}
    end;
parse_TypeConstraints([H|_T],_) ->
    throw({asn1_error,{get_line(H),get(asn1_module),
		       [got,get_token(H),expected,identifier]}}).

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({_,Pos,Token}) when is_integer(Pos),is_atom(Token) ->
    Pos;
get_line({Token,Pos}) when is_integer(Pos),is_atom(Token) ->
    Pos;
get_line(_) ->
    undefined.

get_token({_,Pos,Token}) when is_integer(Pos),is_atom(Token) ->
    Token;
get_token({'$end',Pos}) when is_integer(Pos) ->
    undefined;
get_token({Token,Pos}) when is_integer(Pos),is_atom(Token) ->
    Token;
get_token(_) ->
    undefined.

prioritize_error(ErrList) ->
    case lists:keymember(asn1_error,1,ErrList) of
	false -> % only asn1_assignment_error -> take the last
	    lists:last(ErrList);
	true -> % contains errors from deeper in a Type
	    NewErrList = [_Err={_,_}|_RestErr] =
		lists:filter(fun({asn1_error,_})->true;(_)->false end,
			     ErrList),
	    SplitErrs =
		lists:splitwith(fun({_,X})->
					case element(1,X) of
					    Int when is_integer(Int) -> true;
					    _ -> false
					end
				end,
				NewErrList),
	    case SplitErrs of
		{[],UndefPosErrs} -> % if no error with Positon exists
		    lists:last(UndefPosErrs);
		{IntPosErrs,_} ->
		    IntPosReasons = lists:map(fun(X)->element(2,X) end,IntPosErrs),
		    SortedReasons = lists:keysort(1,IntPosReasons),
		    {asn1_error,lists:last(SortedReasons)}
	    end
    end.

%% most_prio_error([H={_,Reason}|T],Atom,Err) when is_atom(Atom) ->
%%     most_prio_error(T,element(1,Reason),H);
%% most_prio_error([H={_,Reason}|T],Greatest,Err) ->
%%     case element(1,Reason) of
%% 	Pos when is_integer(Pos),Pos>Greatest ->
%% 	    most_prio_error(


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

%% lookahead_assignment/1 checks that the next sequence of tokens
%% in Token contain a valid assignment or the
%% 'END' token. Otherwise an exception is thrown.
lookahead_assignment([{'END',_}|_Rest]) ->
    ok;
lookahead_assignment(Tokens) ->
    parse_Assignment(Tokens),
    ok.