PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/opensource.apple.com/source/CPANInternal/CPANInternal-105/Convert-ASN1/parser.y

#
Happy | 603 lines | 515 code | 88 blank | 0 comment | 0 complexity | 3507a60d3d497728697892a1aecab031 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, GPL-3.0, MPL-2.0, LGPL-2.0, LGPL-2.1, CC-BY-SA-3.0, IPL-1.0, ISC, AGPL-1.0, AGPL-3.0, JSON, Apache-2.0, 0BSD
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  4. <head>
  5. <title>parser.y</title>
  6. <style type="text/css">
  7. .enscript-comment { font-style: italic; color: rgb(178,34,34); }
  8. .enscript-function-name { font-weight: bold; color: rgb(0,0,255); }
  9. .enscript-variable-name { font-weight: bold; color: rgb(184,134,11); }
  10. .enscript-keyword { font-weight: bold; color: rgb(160,32,240); }
  11. .enscript-reference { font-weight: bold; color: rgb(95,158,160); }
  12. .enscript-string { font-weight: bold; color: rgb(188,143,143); }
  13. .enscript-builtin { font-weight: bold; color: rgb(218,112,214); }
  14. .enscript-type { font-weight: bold; color: rgb(34,139,34); }
  15. .enscript-highlight { text-decoration: underline; color: 0; }
  16. </style>
  17. </head>
  18. <body id="top">
  19. <h1 style="margin:8px;" id="f1">parser.y&nbsp;&nbsp;&nbsp;<span style="font-weight: normal; font-size: 0.5em;">[<a href="?txt">plain text</a>]</span></h1>
  20. <hr/>
  21. <div></div>
  22. <pre>
  23. %token WORD 1
  24. %token CLASS 2
  25. %token SEQUENCE 3
  26. %token SET 4
  27. %token CHOICE 5
  28. %token OF 6
  29. %token IMPLICIT 7
  30. %token EXPLICIT 8
  31. %token OPTIONAL 9
  32. %token LBRACE 10
  33. %token RBRACE 11
  34. %token COMMA 12
  35. %token ANY 13
  36. %token ASSIGN 14
  37. %token NUMBER 15
  38. %token ENUM 16
  39. %token COMPONENTS 17
  40. %token POSTRBRACE 18
  41. %token DEFINED 19
  42. %token BY 20
  43. %{
  44. # Copyright (c) 2000-2005 Graham Barr &lt;<a href="mailto:gbarr@pobox.com">gbarr@pobox.com</a>&gt;. All rights reserved.
  45. # This program is free software; you can redistribute it and/or
  46. # modify it under the same terms as Perl itself.
  47. package Convert::ASN1::parser;
  48. use strict;
  49. use Convert::ASN1 qw(:all);
  50. use vars qw(
  51. $asn $yychar $yyerrflag $yynerrs $yyn @yyss
  52. $yyssp $yystate @yyvs $yyvsp $yylval $yys $yym $yyval
  53. );
  54. BEGIN { Convert::ASN1-&gt;_internal_syms }
  55. my $yydebug=0;
  56. my %yystate;
  57. my %base_type = (
  58. BOOLEAN =&gt; [ asn_encode_tag(ASN_BOOLEAN), opBOOLEAN ],
  59. INTEGER =&gt; [ asn_encode_tag(ASN_INTEGER), opINTEGER ],
  60. BIT_STRING =&gt; [ asn_encode_tag(ASN_BIT_STR), opBITSTR ],
  61. OCTET_STRING =&gt; [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
  62. STRING =&gt; [ asn_encode_tag(ASN_OCTET_STR), opSTRING ],
  63. NULL =&gt; [ asn_encode_tag(ASN_NULL), opNULL ],
  64. OBJECT_IDENTIFIER =&gt; [ asn_encode_tag(ASN_OBJECT_ID), opOBJID ],
  65. REAL =&gt; [ asn_encode_tag(ASN_REAL), opREAL ],
  66. ENUMERATED =&gt; [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
  67. ENUM =&gt; [ asn_encode_tag(ASN_ENUMERATED), opINTEGER ],
  68. 'RELATIVE-OID' =&gt; [ asn_encode_tag(ASN_RELATIVE_OID), opROID ],
  69. SEQUENCE =&gt; [ asn_encode_tag(ASN_SEQUENCE | ASN_CONSTRUCTOR), opSEQUENCE ],
  70. SET =&gt; [ asn_encode_tag(ASN_SET | ASN_CONSTRUCTOR), opSET ],
  71. ObjectDescriptor =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 7), opSTRING ],
  72. UTF8String =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 12), opUTF8 ],
  73. NumericString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 18), opSTRING ],
  74. PrintableString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 19), opSTRING ],
  75. TeletexString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
  76. T61String =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 20), opSTRING ],
  77. VideotexString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 21), opSTRING ],
  78. IA5String =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 22), opSTRING ],
  79. UTCTime =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 23), opUTIME ],
  80. GeneralizedTime =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 24), opGTIME ],
  81. GraphicString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 25), opSTRING ],
  82. VisibleString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
  83. ISO646String =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 26), opSTRING ],
  84. GeneralString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 27), opSTRING ],
  85. CharacterString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
  86. UniversalString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 28), opSTRING ],
  87. BMPString =&gt; [ asn_encode_tag(ASN_UNIVERSAL | 30), opSTRING ],
  88. BCDString =&gt; [ asn_encode_tag(ASN_OCTET_STR), opBCD ],
  89. CHOICE =&gt; [ '', opCHOICE ],
  90. ANY =&gt; [ '', opANY ],
  91. );
  92. # Given an OP, wrap it in a SEQUENCE
  93. sub explicit {
  94. my $op = shift;
  95. my @seq = @$op;
  96. @seq[cTYPE,cCHILD,cVAR,cLOOP] = ('SEQUENCE',[$op],undef,undef);
  97. @{$op}[cTAG,cOPT] = ();
  98. \@seq;
  99. }
  100. %}
  101. %%
  102. top : slist { $$ = { '' =&gt; $1 }; }
  103. | module
  104. ;
  105. module : WORD ASSIGN aitem
  106. {
  107. $$ = { $1, [$3] };
  108. }
  109. | module WORD ASSIGN aitem
  110. {
  111. $$=$1;
  112. $$-&gt;{$2} = [$4];
  113. }
  114. ;
  115. aitem : class plicit anyelem postrb
  116. {
  117. $3-&gt;[cTAG] = $1;
  118. $$ = $2 ? explicit($3) : $3;
  119. }
  120. | celem
  121. ;
  122. anyelem : onelem
  123. | eelem
  124. | oelem
  125. | selem
  126. ;
  127. celem : COMPONENTS OF WORD
  128. {
  129. @{$$ = []}[cTYPE,cCHILD] = ('COMPONENTS', $3);
  130. }
  131. ;
  132. seqset : SEQUENCE
  133. | SET
  134. ;
  135. selem : seqset OF class plicit sselem optional
  136. {
  137. $5-&gt;[cTAG] = $3;
  138. @{$$ = []}[cTYPE,cCHILD,cLOOP,cOPT] = ($1, [$5], 1, $6);
  139. $$ = explicit($$) if $4;
  140. }
  141. ;
  142. sselem : eelem
  143. | oelem
  144. | onelem
  145. ;
  146. onelem : SEQUENCE LBRACE slist RBRACE
  147. {
  148. @{$$ = []}[cTYPE,cCHILD] = ('SEQUENCE', $3);
  149. }
  150. | SET LBRACE slist RBRACE
  151. {
  152. @{$$ = []}[cTYPE,cCHILD] = ('SET', $3);
  153. }
  154. | CHOICE LBRACE nlist RBRACE
  155. {
  156. @{$$ = []}[cTYPE,cCHILD] = ('CHOICE', $3);
  157. }
  158. ;
  159. eelem : ENUM LBRACE elist RBRACE
  160. {
  161. @{$$ = []}[cTYPE] = ('ENUM');
  162. }
  163. ;
  164. oielem : WORD { @{$$ = []}[cTYPE] = $1; }
  165. | SEQUENCE { @{$$ = []}[cTYPE] = $1; }
  166. | SET { @{$$ = []}[cTYPE] = $1; }
  167. | ANY defined
  168. {
  169. @{$$ = []}[cTYPE,cCHILD,cDEFINE] = ('ANY',undef,$2);
  170. }
  171. | ENUM { @{$$ = []}[cTYPE] = $1; }
  172. ;
  173. defined : { $$=undef; }
  174. | DEFINED BY WORD { $$=$3; }
  175. ;
  176. oelem : oielem
  177. ;
  178. nlist : nlist1 { $$ = $1; }
  179. | nlist1 POSTRBRACE { $$ = $1; }
  180. ;
  181. nlist1 : nitem
  182. {
  183. $$ = [ $1 ];
  184. }
  185. | nlist1 POSTRBRACE nitem
  186. {
  187. push @{$$=$1}, $3;
  188. }
  189. | nlist1 COMMA nitem
  190. {
  191. push @{$$=$1}, $3;
  192. }
  193. ;
  194. nitem : WORD class plicit anyelem
  195. {
  196. @{$$=$4}[cVAR,cTAG] = ($1,$2);
  197. $$ = explicit($$) if $3;
  198. }
  199. ;
  200. slist : slist1 { $$ = $1; }
  201. | slist1 POSTRBRACE { $$ = $1; }
  202. ;
  203. slist1 : sitem
  204. {
  205. $$ = [ $1 ];
  206. }
  207. | slist1 COMMA sitem
  208. {
  209. push @{$$=$1}, $3;
  210. }
  211. | slist1 POSTRBRACE sitem
  212. {
  213. push @{$$=$1}, $3;
  214. }
  215. ;
  216. snitem : oelem optional
  217. {
  218. @{$$=$1}[cOPT] = ($2);
  219. }
  220. | eelem
  221. | selem
  222. | onelem
  223. ;
  224. sitem : WORD class plicit snitem
  225. {
  226. @{$$=$4}[cVAR,cTAG] = ($1,$2);
  227. $$-&gt;[cOPT] = $1 if $$-&gt;[cOPT];
  228. $$ = explicit($$) if $3;
  229. }
  230. | celem
  231. | class plicit onelem
  232. {
  233. @{$$=$3}[cTAG] = ($1);
  234. $$ = explicit($$) if $2;
  235. }
  236. ;
  237. optional : { $$ = undef; }
  238. | OPTIONAL { $$ = 1; }
  239. ;
  240. class : { $$ = undef; }
  241. | CLASS
  242. ;
  243. plicit : { $$ = undef; }
  244. | EXPLICIT { $$ = 1; }
  245. | IMPLICIT { $$ = 0; }
  246. ;
  247. elist : eitem {}
  248. | elist COMMA eitem {}
  249. ;
  250. eitem : WORD NUMBER {}
  251. ;
  252. postrb : {}
  253. | POSTRBRACE {}
  254. ;
  255. %%
  256. my %reserved = (
  257. 'OPTIONAL' =&gt; $OPTIONAL,
  258. 'CHOICE' =&gt; $CHOICE,
  259. 'OF' =&gt; $OF,
  260. 'IMPLICIT' =&gt; $IMPLICIT,
  261. 'EXPLICIT' =&gt; $EXPLICIT,
  262. 'SEQUENCE' =&gt; $SEQUENCE,
  263. 'SET' =&gt; $SET,
  264. 'ANY' =&gt; $ANY,
  265. 'ENUM' =&gt; $ENUM,
  266. 'ENUMERATED' =&gt; $ENUM,
  267. 'COMPONENTS' =&gt; $COMPONENTS,
  268. '{' =&gt; $LBRACE,
  269. '}' =&gt; $RBRACE,
  270. ',' =&gt; $COMMA,
  271. '::=' =&gt; $ASSIGN,
  272. 'DEFINED' =&gt; $DEFINED,
  273. 'BY' =&gt; $BY
  274. );
  275. my $reserved = join(&quot;|&quot;, reverse sort grep { /\w/ } keys %reserved);
  276. my %tag_class = (
  277. APPLICATION =&gt; ASN_APPLICATION,
  278. UNIVERSAL =&gt; ASN_UNIVERSAL,
  279. PRIVATE =&gt; ASN_PRIVATE,
  280. CONTEXT =&gt; ASN_CONTEXT,
  281. '' =&gt; ASN_CONTEXT # if not specified, its CONTEXT
  282. );
  283. ;##
  284. ;## This is NOT thread safe !!!!!!
  285. ;##
  286. my $pos;
  287. my $last_pos;
  288. my @stacked;
  289. sub parse {
  290. local(*asn) = \($_[0]);
  291. ($pos,$last_pos,@stacked) = ();
  292. eval {
  293. local $SIG{__DIE__};
  294. compile(verify(yyparse()));
  295. }
  296. }
  297. sub compile_one {
  298. my $tree = shift;
  299. my $ops = shift;
  300. my $name = shift;
  301. foreach my $op (@$ops) {
  302. next unless ref($op) eq 'ARRAY';
  303. bless $op;
  304. my $type = $op-&gt;[cTYPE];
  305. if (exists $base_type{$type}) {
  306. $op-&gt;[cTYPE] = $base_type{$type}-&gt;[1];
  307. $op-&gt;[cTAG] = defined($op-&gt;[cTAG]) ? asn_encode_tag($op-&gt;[cTAG]): $base_type{$type}-&gt;[0];
  308. }
  309. else {
  310. die &quot;Unknown type '$type'\n&quot; unless exists $tree-&gt;{$type};
  311. my $ref = compile_one(
  312. $tree,
  313. $tree-&gt;{$type},
  314. defined($op-&gt;[cVAR]) ? $name . &quot;.&quot; . $op-&gt;[cVAR] : $name
  315. );
  316. if (defined($op-&gt;[cTAG]) &amp;&amp; $ref-&gt;[0][cTYPE] == opCHOICE) {
  317. @{$op}[cTYPE,cCHILD] = (opSEQUENCE,$ref);
  318. }
  319. else {
  320. @{$op}[cTYPE,cCHILD,cLOOP] = @{$ref-&gt;[0]}[cTYPE,cCHILD,cLOOP];
  321. }
  322. $op-&gt;[cTAG] = defined($op-&gt;[cTAG]) ? asn_encode_tag($op-&gt;[cTAG]): $ref-&gt;[0][cTAG];
  323. }
  324. $op-&gt;[cTAG] |= chr(ASN_CONSTRUCTOR)
  325. if length $op-&gt;[cTAG] &amp;&amp; ($op-&gt;[cTYPE] == opSET || $op-&gt;[cTYPE] == opSEQUENCE);
  326. if ($op-&gt;[cCHILD]) {
  327. ;# If we have children we are one of
  328. ;# opSET opSEQUENCE opCHOICE
  329. compile_one($tree, $op-&gt;[cCHILD], defined($op-&gt;[cVAR]) ? $name . &quot;.&quot; . $op-&gt;[cVAR] : $name);
  330. ;# If a CHOICE is given a tag, then it must be EXPLICIT
  331. if ($op-&gt;[cTYPE] == opCHOICE &amp;&amp; defined($op-&gt;[cTAG]) &amp;&amp; length($op-&gt;[cTAG])) {
  332. $op = bless explicit($op);
  333. $op-&gt;[cTYPE] = opSEQUENCE;
  334. }
  335. if ( @{$op-&gt;[cCHILD]} &gt; 1) {
  336. ;#if ($op-&gt;[cTYPE] != opSEQUENCE) {
  337. ;# Here we need to flatten CHOICEs and check that SET and CHOICE
  338. ;# do not contain duplicate tags
  339. ;#}
  340. if ($op-&gt;[cTYPE] == opSET) {
  341. ;# In case we do CER encoding we order the SET elements by thier tags
  342. my @tags = map {
  343. length($_-&gt;[cTAG])
  344. ? $_-&gt;[cTAG]
  345. : $_-&gt;[cTYPE] == opCHOICE
  346. ? (sort map { $_-&gt;[cTAG] } $_-&gt;[cCHILD])[0]
  347. : ''
  348. } @{$op-&gt;[cCHILD]};
  349. @{$op-&gt;[cCHILD]} = @{$op-&gt;[cCHILD]}[sort { $tags[$a] cmp $tags[$b] } 0..$#tags];
  350. }
  351. }
  352. else {
  353. ;# A SET of one element can be treated the same as a SEQUENCE
  354. $op-&gt;[cTYPE] = opSEQUENCE if $op-&gt;[cTYPE] == opSET;
  355. }
  356. }
  357. }
  358. $ops;
  359. }
  360. sub compile {
  361. my $tree = shift;
  362. ;# The tree should be valid enough to be able to
  363. ;# - resolve references
  364. ;# - encode tags
  365. ;# - verify CHOICEs do not contain duplicate tags
  366. ;# once references have been resolved, and also due to
  367. ;# flattening of COMPONENTS, it is possible for an op
  368. ;# to appear in multiple places. So once an op is
  369. ;# compiled we bless it. This ensure we dont try to
  370. ;# compile it again.
  371. while(my($k,$v) = each %$tree) {
  372. compile_one($tree,$v,$k);
  373. }
  374. $tree;
  375. }
  376. sub verify {
  377. my $tree = shift or return;
  378. my $err = &quot;&quot;;
  379. ;# Well it parsed correctly, now we
  380. ;# - check references exist
  381. ;# - flatten COMPONENTS OF (checking for loops)
  382. ;# - check for duplicate var names
  383. while(my($name,$ops) = each %$tree) {
  384. my $stash = {};
  385. my @scope = ();
  386. my $path = &quot;&quot;;
  387. my $idx = 0;
  388. while($ops) {
  389. if ($idx &lt; @$ops) {
  390. my $op = $ops-&gt;[$idx++];
  391. my $var;
  392. if (defined ($var = $op-&gt;[cVAR])) {
  393. $err .= &quot;$name: $path.$var used multiple times\n&quot;
  394. if $stash-&gt;{$var}++;
  395. }
  396. if (defined $op-&gt;[cCHILD]) {
  397. if (ref $op-&gt;[cCHILD]) {
  398. push @scope, [$stash, $path, $ops, $idx];
  399. if (defined $var) {
  400. $stash = {};
  401. $path .= &quot;.&quot; . $var;
  402. }
  403. $idx = 0;
  404. $ops = $op-&gt;[cCHILD];
  405. }
  406. elsif ($op-&gt;[cTYPE] eq 'COMPONENTS') {
  407. splice(@$ops,--$idx,1,expand_ops($tree, $op-&gt;[cCHILD]));
  408. }
  409. else {
  410. die &quot;Internal error\n&quot;;
  411. }
  412. }
  413. }
  414. else {
  415. my $s = pop @scope
  416. or last;
  417. ($stash,$path,$ops,$idx) = @$s;
  418. }
  419. }
  420. }
  421. die $err if length $err;
  422. $tree;
  423. }
  424. sub expand_ops {
  425. my $tree = shift;
  426. my $want = shift;
  427. my $seen = shift || { };
  428. die &quot;COMPONENTS OF loop $want\n&quot; if $seen-&gt;{$want}++;
  429. die &quot;Undefined macro $want\n&quot; unless exists $tree-&gt;{$want};
  430. my $ops = $tree-&gt;{$want};
  431. die &quot;Bad macro for COMPUNENTS OF '$want'\n&quot;
  432. unless @$ops == 1
  433. &amp;&amp; ($ops-&gt;[0][cTYPE] eq 'SEQUENCE' || $ops-&gt;[0][cTYPE] eq 'SET')
  434. &amp;&amp; ref $ops-&gt;[0][cCHILD];
  435. $ops = $ops-&gt;[0][cCHILD];
  436. for(my $idx = 0 ; $idx &lt; @$ops ; ) {
  437. my $op = $ops-&gt;[$idx++];
  438. if ($op-&gt;[cTYPE] eq 'COMPONENTS') {
  439. splice(@$ops,--$idx,1,expand_ops($tree, $op-&gt;[cCHILD], $seen));
  440. }
  441. }
  442. @$ops;
  443. }
  444. sub _yylex {
  445. my $ret = &amp;_yylex;
  446. warn $ret;
  447. $ret;
  448. }
  449. sub yylex {
  450. return shift @stacked if @stacked;
  451. while ($asn =~ /\G(?:
  452. (\s+|--[^\n]*)
  453. |
  454. ([,{}]|::=)
  455. |
  456. ($reserved)\b
  457. |
  458. (
  459. (?:OCTET|BIT)\s+STRING
  460. |
  461. OBJECT\s+IDENTIFIER
  462. |
  463. RELATIVE-OID
  464. )\b
  465. |
  466. (\w+(?:-\w+)*)
  467. |
  468. \[\s*
  469. (
  470. (?:(?:APPLICATION|PRIVATE|UNIVERSAL|CONTEXT)\s+)?
  471. \d+
  472. )
  473. \s*\]
  474. |
  475. \((\d+)\)
  476. )/sxgo
  477. ) {
  478. ($last_pos,$pos) = ($pos,pos($asn));
  479. next if defined $1; # comment or whitespace
  480. if (defined $2 or defined $3) {
  481. # A comma is not required after a '}' so to aid the
  482. # parser we insert a fake token after any '}'
  483. push @stacked, $POSTRBRACE if defined $2 and $+ eq '}';
  484. return $reserved{$yylval = $+};
  485. }
  486. if (defined $4) {
  487. ($yylval = $+) =~ s/\s+/_/g;
  488. return $WORD;
  489. }
  490. if (defined $5) {
  491. $yylval = $+;
  492. return $WORD;
  493. }
  494. if (defined $6) {
  495. my($class,$num) = ($+ =~ /^([A-Z]*)\s*(\d+)$/);
  496. $yylval = asn_tag($tag_class{$class}, $num);
  497. return $CLASS;
  498. }
  499. if (defined $7) {
  500. $yylval = $+;
  501. return $NUMBER;
  502. }
  503. die &quot;Internal error\n&quot;;
  504. }
  505. die &quot;Parse error before &quot;,substr($asn,$pos,40),&quot;\n&quot;
  506. unless $pos == length($asn);
  507. 0
  508. }
  509. sub yyerror {
  510. die @_,&quot; &quot;,substr($asn,$last_pos,40),&quot;\n&quot;;
  511. }
  512. 1;
  513. </pre>
  514. <hr />
  515. </body></html>