1######################## 2# ASN.1 Parse::Yapp parser 3# Copyright (C) Stefan (metze) Metzmacher <metze@samba.org> 4# released under the GNU GPL version 3 or later 5 6 7 8# the precedence actually doesn't matter at all for this grammer, but 9# by providing a precedence we reduce the number of conflicts 10# enormously 11%left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ']' ':' ',' ';' 12 13 14################ 15# grammer 16%% 17 18asn1: 19 identifier asn1_definitions asn1_delimitter asn1_begin asn1_decls asn1_end 20 {{ 21 "OBJECT" => "ASN1_DEFINITION", 22 "IDENTIFIER" => $_[1], 23 "DATA" => $_[5] 24 }} 25; 26 27asn1_delimitter: 28 delimitter 29; 30 31asn1_definitions: 32 'DEFINITIONS' 33; 34 35asn1_begin: 36 'BEGIN' 37; 38 39asn1_end: 40 'END' 41; 42 43asn1_decls: 44 asn1_def 45 { [ $_[1] ] } 46 | asn1_decls asn1_def 47 { push(@{$_[1]}, $_[2]); $_[1] } 48; 49 50 51 52asn1_def: 53 asn1_target asn1_delimitter asn1_application asn1_type 54 {{ 55 "OBJECT" => "ASN1_DEF", 56 "IDENTIFIER" => $_[1], 57 "APPLICATION" => $_[3], 58 "STRUCTURE" => $_[4] 59 }} 60; 61 62asn1_target: 63 identifier 64; 65 66asn1_application: 67 #empty 68 | '[' 'APPLICATION' constant ']' 69 { $_[3] } 70; 71 72asn1_type: 73 asn1_boolean 74 | asn1_integer 75 | asn1_bit_string 76 | asn1_octet_string 77 | asn1_null 78 | asn1_object_identifier 79 | asn1_real 80 | asn1_enumerated 81 | asn1_sequence 82 | identifier 83; 84 85asn1_boolean: 86 'BOOLEAN' 87 {{ 88 "TYPE" => "BOOLEAN", 89 "TAG" => 1 90 }} 91; 92 93asn1_integer: 94 'INTEGER' 95 {{ 96 "TYPE" => "INTEGER", 97 "TAG" => 2 98 }} 99 | 'INTEGER' '(' constant '.' '.' constant ')' 100 {{ 101 "TYPE" => "INTEGER", 102 "TAG" => 2, 103 "RANGE_LOW" => $_[3], 104 "RENAGE_HIGH" => $_[6] 105 }} 106; 107 108asn1_bit_string: 109 'BIT' 'STRING' 110 {{ 111 "TYPE" => "BIT STRING", 112 "TAG" => 3 113 }} 114; 115 116asn1_octet_string: 117 'OCTET' 'STRING' 118 {{ 119 "TYPE" => "OCTET STRING", 120 "TAG" => 4 121 }} 122; 123 124asn1_null: 125 'NULL' 126 {{ 127 "TYPE" => "NULL", 128 "TAG" => 5 129 }} 130; 131 132asn1_object_identifier: 133 'OBJECT' 'IDENTIFIER' 134 {{ 135 "TYPE" => "OBJECT IDENTIFIER", 136 "TAG" => 6 137 }} 138; 139 140asn1_real: 141 'REAL' 142 {{ 143 "TYPE" => "REAL", 144 "TAG" => 9 145 }} 146; 147 148asn1_enumerated: 149 'ENUMERATED' 150 {{ 151 "TYPE" => "ENUMERATED", 152 "TAG" => 10 153 }} 154; 155 156asn1_sequence: 157 'SEQUENCE' '{' asn1_var_dec_list '}' 158 {{ 159 "TYPE" => "SEQUENCE", 160 "TAG" => 16, 161 "STRUCTURE" => $_[3] 162 }} 163; 164 165asn1_var_dec_list: 166 asn1_var_dec 167 { [ $_[1] ] } 168 | asn1_var_dec_list ',' asn1_var_dec 169 { push(@{$_[1]}, $_[3]); $_[1] } 170; 171 172asn1_var_dec: 173 identifier asn1_type 174 {{ 175 "NAME" => $_[1], 176 "TYPE" => $_[2] 177 }} 178; 179 180anytext: #empty { "" } 181 | identifier | constant | text 182 | anytext '-' anytext { "$_[1]$_[2]$_[3]" } 183 | anytext '.' anytext { "$_[1]$_[2]$_[3]" } 184 | anytext '*' anytext { "$_[1]$_[2]$_[3]" } 185 | anytext '>' anytext { "$_[1]$_[2]$_[3]" } 186 | anytext '|' anytext { "$_[1]$_[2]$_[3]" } 187 | anytext '&' anytext { "$_[1]$_[2]$_[3]" } 188 | anytext '/' anytext { "$_[1]$_[2]$_[3]" } 189 | anytext '+' anytext { "$_[1]$_[2]$_[3]" } 190 | anytext '(' anytext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" } 191; 192 193delimitter: DELIMITTER 194; 195 196identifier: IDENTIFIER 197; 198 199constant: CONSTANT 200; 201 202text: TEXT { "\"$_[1]\"" } 203; 204 205##################################### 206# start code 207%% 208 209use util; 210 211sub _ASN1_Error { 212 if (exists $_[0]->YYData->{ERRMSG}) { 213 print $_[0]->YYData->{ERRMSG}; 214 delete $_[0]->YYData->{ERRMSG}; 215 return; 216 }; 217 my $line = $_[0]->YYData->{LINE}; 218 my $last_token = $_[0]->YYData->{LAST_TOKEN}; 219 my $file = $_[0]->YYData->{INPUT_FILENAME}; 220 221 print "$file:$line: Syntax error near '$last_token'\n"; 222} 223 224sub _ASN1_Lexer($) 225{ 226 my($parser)=shift; 227 228 $parser->YYData->{INPUT} 229 or return('',undef); 230 231again: 232 $parser->YYData->{INPUT} =~ s/^[ \t]*//; 233 234 for ($parser->YYData->{INPUT}) { 235 if (/^\#/) { 236 if (s/^\# (\d+) \"(.*?)\"( \d+|)//) { 237 $parser->YYData->{LINE} = $1-1; 238 $parser->YYData->{INPUT_FILENAME} = $2; 239 goto again; 240 } 241 if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) { 242 $parser->YYData->{LINE} = $1-1; 243 $parser->YYData->{INPUT_FILENAME} = $2; 244 goto again; 245 } 246 if (s/^(\#.*)$//m) { 247 goto again; 248 } 249 } 250 if (s/^(\n)//) { 251 $parser->YYData->{LINE}++; 252 goto again; 253 } 254 if (s/^(--.*\n)//) { 255 $parser->YYData->{LINE}++; 256 goto again; 257 } 258 if (s/^(::=)//) { 259 $parser->YYData->{LAST_TOKEN} = $1; 260 return('DELIMITTER',$1); 261 } 262 if (s/^\"(.*?)\"//) { 263 $parser->YYData->{LAST_TOKEN} = $1; 264 return('TEXT',$1); 265 } 266 if (s/^(\d+)(\W|$)/$2/) { 267 $parser->YYData->{LAST_TOKEN} = $1; 268 return('CONSTANT',$1); 269 } 270 if (s/^([\w_-]+)//) { 271 $parser->YYData->{LAST_TOKEN} = $1; 272 if ($1 =~ 273 /^(SEQUENCE|INTEGER|OCTET|STRING| 274 APPLICATION|OPTIONAL|NULL|COMPONENTS|OF| 275 BOOLEAN|ENUMERATED|CHOISE|REAL|BIT|OBJECT|IDENTIFIER| 276 DEFAULT|FALSE|TRUE|SET|DEFINITIONS|BEGIN|END)$/x) { 277 return $1; 278 } 279 return('IDENTIFIER',$1); 280 } 281 if (s/^(.)//s) { 282 $parser->YYData->{LAST_TOKEN} = $1; 283 return($1,$1); 284 } 285 } 286} 287 288sub parse_asn1($$) 289{ 290 my $self = shift; 291 my $filename = shift; 292 293 my $saved_delim = $/; 294 undef $/; 295 my $cpp = $ENV{CPP}; 296 if (! defined $cpp) { 297 $cpp = "cpp" 298 } 299 my $data = `$cpp -xc $filename`; 300 $/ = $saved_delim; 301 302 $self->YYData->{INPUT} = $data; 303 $self->YYData->{LINE} = 0; 304 $self->YYData->{LAST_TOKEN} = "NONE"; 305 return $self->YYParse( yylex => \&_ASN1_Lexer, yyerror => \&_ASN1_Error ); 306} 307