Commit | Line | Data |
---|---|---|
970ed795 EL |
1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2014 Ericsson Telecom AB | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | ******************************************************************************/ | |
8 | /* | |
9 | * ASN1:1997 lexical analyzer | |
10 | * Written by Matyas Forstner | |
11 | * 20021115 | |
12 | */ | |
13 | ||
14 | %option stack | |
15 | %option yylineno | |
16 | %option noyywrap | |
17 | %option nounput | |
18 | %option never-interactive | |
19 | %option prefix="asn1_yy" | |
20 | ||
21 | %{ /* ****************** C declarations ***************** */ | |
22 | ||
23 | #include "../error.h" | |
24 | #include "../string.hh" | |
25 | #include "../Identifier.hh" | |
26 | #include "../Setting.hh" | |
27 | #include "../Value.hh" | |
28 | #include "TokenBuf.hh" | |
29 | ||
30 | using namespace Common; | |
31 | using namespace Asn; | |
32 | ||
33 | /** | |
34 | * The name of the file which is under parsing. | |
35 | */ | |
36 | const char *asn1_infile; | |
37 | /** | |
38 | * When this flag is set, then the special internal TITAN-tokens are | |
39 | * handled. | |
40 | */ | |
41 | bool asn1_yy_parse_internal=false; | |
42 | ||
43 | void asn1_init(); | |
44 | void asn1_free(); | |
45 | void asn1la_newfile(const char *filename); | |
46 | void asn1la_newtokenbuf(TokenBuf *tb); | |
47 | int asn1_yylex_my(); | |
48 | ||
49 | static int commentlevel=0; | |
50 | static int commentbeginlineno=0; | |
51 | static TokenBuf *asn1_tokenbuf=0; | |
52 | static TokenBuf *asn1_tokenbuf_curr=0; | |
53 | ||
54 | static void id_replace_underscores(char *s); | |
55 | static void bhstring_remove_whitespaces(char *s); | |
56 | static void cstring_remove_newlines(char *s); | |
57 | ||
58 | %} /* ***************** definitions ***************** */ | |
59 | ||
60 | /* start conditions */ | |
61 | %x SC_LINECOMMENT SC_COMMENT SC_COMMENT_END | |
62 | %s SC_TITAN | |
63 | ||
64 | /* 11.1.6 */ | |
65 | WHITESPACE [ \t\x0A\x0B\x0C\x0D]+ | |
66 | NEWLINE [\x0A\x0B\x0C\x0D] | |
67 | ||
68 | /* 11.2 */ | |
69 | UPPERIDENTIFIER [A-Z]([\-_]?[A-Za-z0-9]+)* | |
70 | /* 11.3 */ | |
71 | LOWERIDENTIFIER [a-z]([\-_]?[A-Za-z0-9]+)* | |
72 | ||
73 | /* X.681, 7.1 */ | |
74 | ampUPPERIDENTIFIER \&{UPPERIDENTIFIER} | |
75 | ampLOWERIDENTIFIER \&{LOWERIDENTIFIER} | |
76 | ||
77 | /* 11.8 */ | |
78 | NUMBER ([1-9][0-9]*)|0 | |
79 | /* 11.9 */ | |
80 | REALNUMBER {NUMBER}(\.[0-9]+)?([eE][+\-]?{NUMBER})? | |
81 | /* 11.10 */ | |
82 | BSTRING '([01]|{WHITESPACE})*'B | |
83 | BSTRING_BAD '[^']*'B | |
84 | /* 11.12 */ | |
85 | HSTRING '([0-9A-F]|{WHITESPACE})*'H | |
86 | HSTRING_BAD '[^']*'H | |
87 | HSTRING_BAD_OSTRING '([0-9A-F]|{WHITESPACE})*'O | |
88 | ||
89 | /* 11.14 */ | |
90 | CSTRING \"([^"]|(\"\"))*\" | |
91 | CSTRING_BAD '[^']*' | |
92 | ||
93 | SEPARATOR ({WHITESPACE}|{COMMENT}) | |
94 | ||
95 | PERPERCOMMENT "//"[^\x0A\x0B\x0C\x0D]*{NEWLINE} | |
96 | ||
97 | TITAN "$#&&&(#TITAN$#&&^#% " | |
98 | TITAN_ID [A-Za-z0-9 \-_]+ | |
99 | ||
100 | %% /* ***************** rules ************************* */ | |
101 | ||
102 | {TITAN} { | |
103 | if(asn1_yy_parse_internal) | |
104 | yy_push_state(SC_TITAN); | |
105 | else { | |
106 | Location loc(asn1_infile, yylineno); | |
107 | loc.error("Unexpected `%s'.", yytext); | |
108 | } | |
109 | } | |
110 | ||
111 | <SC_TITAN> /* -------- SC_TITAN scope -------------- */ | |
112 | { | |
113 | ||
114 | "Assignments" { | |
115 | yy_pop_state(); | |
116 | return KW_TITAN_Assignments; | |
117 | } | |
118 | ||
119 | "UpperIdentifier\""{TITAN_ID}"\"" { | |
120 | yy_pop_state(); | |
121 | yytext[strlen(yytext)-1]='\0'; | |
122 | yylval.id=new Identifier(Identifier::ID_ASN, string(yytext+16)); | |
123 | return TOK_UpperIdentifier; | |
124 | } | |
125 | ||
126 | } /* ------------------- End of SC_TITAN scope -------- */ | |
127 | ||
128 | {WHITESPACE} | |
129 | ||
130 | "--" { | |
131 | yy_push_state(SC_LINECOMMENT); | |
132 | } | |
133 | ||
134 | "/*" { | |
135 | commentlevel=1; | |
136 | commentbeginlineno=yylineno; | |
137 | yy_push_state(SC_COMMENT); | |
138 | } | |
139 | ||
140 | {PERPERCOMMENT} { | |
141 | Location loc(asn1_infile, yylineno-1); | |
142 | loc.error("This style of comment is not permitted in ASN.1"); | |
143 | } | |
144 | ||
145 | ||
146 | "::=" {return TOK_Assignment;} | |
147 | ":=" { | |
148 | Location loc(asn1_infile, yylineno); | |
149 | loc.error("`:=' is not valid in ASN.1. Did you mean `::='?"); | |
150 | return TOK_Assignment; | |
151 | } | |
152 | "..." {return TOK_Ellipsis;} | |
153 | ".." {return TOK_RangeSeparator;} | |
154 | "[[" {return TOK_LeftVersionBrackets;} | |
155 | "]]" {return TOK_RightVersionBrackets;} | |
156 | "{" {return '{';} | |
157 | "}" {return '}';} | |
158 | "(" {return '(';} | |
159 | ")" {return ')';} | |
160 | "[" {return '[';} | |
161 | "]" {return ']';} | |
162 | "," {return ',';} | |
163 | "." {return '.';} | |
164 | "-" {return '-';} | |
165 | ":" {return ':';} | |
166 | ";" {return ';';} | |
167 | "@" {return '@';} | |
168 | "|" {return '|';} | |
169 | "!" {return '!';} | |
170 | "^" {return '^';} | |
171 | "<" {return '<';} | |
172 | ">" {return '>';} | |
173 | ||
174 | "ABSENT" {return KW_ABSENT;} | |
175 | /* | |
176 | "ABSTRACT-SYNTAX" {return KW_ABSTRACT_SYNTAX;} | |
177 | */ | |
178 | "ALL" {return KW_ALL;} | |
179 | "ANY" {return KW_ANY;} | |
180 | "APPLICATION" {return KW_APPLICATION;} | |
181 | "AUTOMATIC" {return KW_AUTOMATIC;} | |
182 | "BEGIN" {return KW_BEGIN;} | |
183 | "BIT" {return KW_BIT;} | |
184 | "BMPString" {return KW_BMPString;} | |
185 | "BOOLEAN" {return KW_BOOLEAN;} | |
186 | "BY" {return KW_BY;} | |
187 | "CHARACTER" {return KW_CHARACTER;} | |
188 | "CHOICE" {return KW_CHOICE;} | |
189 | "CLASS" {return KW_CLASS;} | |
190 | "COMPONENT" {return KW_COMPONENT;} | |
191 | "COMPONENTS" {return KW_COMPONENTS;} | |
192 | "CONSTRAINED" {return KW_CONSTRAINED;} | |
193 | "CONTAINING" {return KW_CONTAINING;} | |
194 | "DEFAULT" {return KW_DEFAULT;} | |
195 | "DEFINED" {return KW_DEFINED;} | |
196 | "DEFINITIONS" {return KW_DEFINITIONS;} | |
197 | "EMBEDDED" {return KW_EMBEDDED;} | |
198 | "ENCODED" {return KW_ENCODED;} | |
199 | "END" {return KW_END;} | |
200 | "ENUMERATED" {return KW_ENUMERATED;} | |
201 | "EXCEPT" {return KW_EXCEPT;} | |
202 | "EXPLICIT" {return KW_EXPLICIT;} | |
203 | "EXPORTS" {return KW_EXPORTS;} | |
204 | "EXTENSIBILITY" {return KW_EXTENSIBILITY;} | |
205 | "EXTERNAL" {return KW_EXTERNAL;} | |
206 | "FALSE" {return KW_FALSE;} | |
207 | "FROM" {return KW_FROM;} | |
208 | "GeneralizedTime" {return KW_GeneralizedTime;} | |
209 | "GeneralString" {return KW_GeneralString;} | |
210 | "GraphicString" {return KW_GraphicString;} | |
211 | "IA5String" {return KW_IA5String;} | |
212 | "IDENTIFIER" {return KW_IDENTIFIER;} | |
213 | "IMPLICIT" {return KW_IMPLICIT;} | |
214 | "IMPLIED" {return KW_IMPLIED;} | |
215 | "IMPORTS" {return KW_IMPORTS;} | |
216 | "INCLUDES" {return KW_INCLUDES;} | |
217 | "INSTANCE" {return KW_INSTANCE;} | |
218 | "INTEGER" {return KW_INTEGER;} | |
219 | "INTERSECTION" {return KW_INTERSECTION;} | |
220 | "ISO646String" {return KW_ISO646String;} | |
221 | "MAX" {return KW_MAX;} | |
222 | "MIN" {return KW_MIN;} | |
223 | "MINUS-INFINITY" {return KW_MINUS_INFINITY;} | |
224 | "NOT-A-NUMBER" {return KW_NOT_A_NUMBER;} | |
225 | "NULL" {return KW_NULL;} | |
226 | "NumericString" {return KW_NumericString;} | |
227 | "OBJECT" {return KW_OBJECT;} | |
228 | "ObjectDescriptor" {return KW_ObjectDescriptor;} | |
229 | "OCTET" {return KW_OCTET;} | |
230 | "OF" {return KW_OF;} | |
231 | "OPTIONAL" {return KW_OPTIONAL;} | |
232 | "PATTERN" {return KW_PATTERN;} | |
233 | "PDV" {return KW_PDV;} | |
234 | "PLUS-INFINITY" {return KW_PLUS_INFINITY;} | |
235 | "PRESENT" {return KW_PRESENT;} | |
236 | "PrintableString" {return KW_PrintableString;} | |
237 | "PRIVATE" {return KW_PRIVATE;} | |
238 | "REAL" {return KW_REAL;} | |
239 | "RELATIVE-OID" {return KW_RELATIVE_OID;} | |
240 | "SEQUENCE" {return KW_SEQUENCE;} | |
241 | "SET" {return KW_SET;} | |
242 | "SIZE" {return KW_SIZE;} | |
243 | "STRING" {return KW_STRING;} | |
244 | "SYNTAX" {return KW_SYNTAX;} | |
245 | "T61String" {return KW_T61String;} | |
246 | "TAGS" {return KW_TAGS;} | |
247 | "TeletexString" {return KW_TeletexString;} | |
248 | "TRUE" {return KW_TRUE;} | |
249 | /* | |
250 | "TYPE-IDENTIFIER" {return KW_TYPE_IDENTIFIER;} | |
251 | */ | |
252 | "UNION" {return KW_UNION;} | |
253 | "UNIQUE" {return KW_UNIQUE;} | |
254 | "UNIVERSAL" {return KW_UNIVERSAL;} | |
255 | "UniversalString" {return KW_UniversalString;} | |
256 | "UTCTime" {return KW_UTCTime;} | |
257 | "UTF8String" {return KW_UTF8String;} | |
258 | "VideotexString" {return KW_VideotexString;} | |
259 | "VisibleString" {return KW_VisibleString;} | |
260 | "WITH" {return KW_WITH;} | |
261 | ||
262 | {LOWERIDENTIFIER} { | |
263 | id_replace_underscores(yytext); | |
264 | yylval.id=new Identifier(Identifier::ID_ASN, string(yytext)); | |
265 | return TOK_LowerIdentifier; | |
266 | } | |
267 | ||
268 | {UPPERIDENTIFIER} { | |
269 | id_replace_underscores(yytext); | |
270 | yylval.id=new Identifier(Identifier::ID_ASN, string(yytext)); | |
271 | return TOK_UpperIdentifier; | |
272 | } | |
273 | ||
274 | {ampUPPERIDENTIFIER} { | |
275 | id_replace_underscores(yytext); | |
276 | yylval.id=new Identifier(Identifier::ID_ASN, string(yytext)); | |
277 | return TOK_ampUpperIdentifier; | |
278 | } | |
279 | ||
280 | {ampLOWERIDENTIFIER} { | |
281 | id_replace_underscores(yytext); | |
282 | yylval.id=new Identifier(Identifier::ID_ASN, string(yytext)); | |
283 | return TOK_ampLowerIdentifier; | |
284 | } | |
285 | ||
286 | {NUMBER} { | |
287 | Location loc(asn1_infile, yylineno); | |
288 | yylval.i = new int_val_t(yytext, loc); | |
289 | return TOK_Number; | |
290 | } | |
291 | ||
292 | {REALNUMBER} { | |
293 | Location loc(asn1_infile, yylineno); | |
294 | yylval.value = new Value(Value::V_REAL, string2Real(yytext, loc)); | |
295 | return TOK_RealNumber; | |
296 | } | |
297 | ||
298 | {BSTRING} { | |
299 | bhstring_remove_whitespaces(yytext); | |
300 | yytext[strlen(yytext)-2]='\0'; | |
301 | yylval.value=new Value(Value::V_BSTR, new string(yytext+1)); | |
302 | return TOK_BString; | |
303 | } | |
304 | ||
305 | {BSTRING_BAD} { | |
306 | Location loc(asn1_infile, yylineno); | |
307 | loc.error("Invalid bstring: %s.", yytext); | |
308 | yylval.value=new Value(Value::V_BSTR, new string()); | |
309 | return TOK_HString; | |
310 | } | |
311 | ||
312 | {HSTRING} { | |
313 | bhstring_remove_whitespaces(yytext); | |
314 | yytext[strlen(yytext)-2]='\0'; | |
315 | yylval.value=new Value(Value::V_HSTR, new string(yytext+1)); | |
316 | return TOK_HString; | |
317 | } | |
318 | ||
319 | {HSTRING_BAD} { | |
320 | Location loc(asn1_infile, yylineno); | |
321 | loc.error("Invalid hstring: %s.", yytext); | |
322 | yylval.value=new Value(Value::V_HSTR, new string()); | |
323 | return TOK_HString; | |
324 | } | |
325 | ||
326 | {HSTRING_BAD_OSTRING} { | |
327 | string ostr(yytext); | |
328 | ostr[ostr.size()-1]='H'; | |
329 | Location loc(asn1_infile, yylineno); | |
330 | loc.error("Invalid suffix `O' in %s. Did you mean the hstring %s?", | |
331 | yytext, ostr.c_str()); | |
332 | bhstring_remove_whitespaces(yytext); | |
333 | yytext[strlen(yytext)-2]='\0'; | |
334 | yylval.value=new Value(Value::V_HSTR, new string(yytext+1)); | |
335 | return TOK_HString; | |
336 | } | |
337 | ||
338 | {CSTRING} { | |
339 | yytext[strlen(yytext)-1]='\0'; | |
340 | cstring_remove_newlines(yytext+1); | |
341 | yylval.str=new string(yytext+1); | |
342 | return TOK_CString; | |
343 | } | |
344 | ||
345 | {CSTRING_BAD} { | |
346 | Location loc(asn1_infile, yylineno); | |
347 | loc.error("Invalid cstring: %s. Perhaps you wanted to use quotation" | |
348 | " marks (\") instead of apostrophes (')?", yytext); | |
349 | yytext[strlen(yytext)-1]='\0'; | |
350 | yylval.str=new string(yytext+1); | |
351 | return TOK_CString; | |
352 | } | |
353 | ||
354 | "'" {return '\'';} | |
355 | "\"" {return '"';} | |
356 | ||
357 | "*/" { | |
358 | Location loc(asn1_infile, yylineno); | |
359 | loc.error("Unmatched `*/'"); | |
360 | } | |
361 | ||
362 | . { | |
363 | Location loc(asn1_infile, yylineno); | |
364 | loc.error("`%c' (0x%02X) character is not used in ASN.1", | |
365 | (unsigned char)yytext[0]>31?(unsigned char)yytext[0]:'?', | |
366 | (unsigned char)yytext[0]); | |
367 | } | |
368 | ||
369 | <INITIAL><<EOF>> { | |
370 | return 0; | |
371 | } | |
372 | ||
373 | <SC_LINECOMMENT> /* -------- SC_LINECOMMENT scope -------------- */ | |
374 | { | |
375 | ||
376 | "--"|{NEWLINE} { | |
377 | yy_pop_state(); | |
378 | } | |
379 | ||
380 | <<EOF>> { | |
381 | Location loc(asn1_infile, yylineno); | |
382 | loc.error("Unterminated `--' (missing newline at the end of file)"); | |
383 | yy_pop_state(); | |
384 | return 0; | |
385 | } | |
386 | ||
387 | . | |
388 | ||
389 | } /* ------------------- End of SC_LINECOMMENT scope --------*/ | |
390 | ||
391 | <SC_COMMENT,SC_COMMENT_END><<EOF>> { | |
392 | Location loc(asn1_infile, commentbeginlineno); | |
393 | loc.error("Unmatched `/*'"); | |
394 | while(yy_top_state()!=INITIAL) yy_pop_state(); | |
395 | yy_pop_state(); | |
396 | return 0; | |
397 | } | |
398 | ||
399 | <SC_COMMENT> /* -------- SC_COMMENT scope -------------- */ | |
400 | { | |
401 | ||
402 | "/*" { | |
403 | commentlevel++; | |
404 | } | |
405 | ||
406 | "*" {yy_push_state(SC_COMMENT_END);} | |
407 | ||
408 | [^*] | |
409 | ||
410 | } /* ------------------- End of SC_COMMENT scope --------*/ | |
411 | ||
412 | <SC_COMMENT_END> /* ----- SC_COMMENT_END scope -------------- */ | |
413 | { | |
414 | ||
415 | "*" | |
416 | ||
417 | "/" { | |
418 | yy_pop_state(); | |
419 | commentlevel--; | |
420 | if(!commentlevel) yy_pop_state(); | |
421 | } | |
422 | ||
423 | [^*/] {yy_pop_state();} | |
424 | ||
425 | } /* ------------------- End of SC_COMMENT_END scope --------*/ | |
426 | ||
427 | %% | |
428 | ||
429 | void asn1_init() | |
430 | { | |
431 | asn1_infile=0; | |
432 | asn1_tokenbuf=new TokenBuf(); | |
433 | Asn::Assignments::create_spec_asss(); | |
434 | } | |
435 | ||
436 | void asn1_free() | |
437 | { | |
438 | Asn::Assignments::destroy_spec_asss(); | |
439 | delete asn1_tokenbuf; | |
440 | } | |
441 | ||
442 | void asn1la_newfile(const char *filename) | |
443 | { | |
444 | asn1_tokenbuf->reset(filename); | |
445 | asn1la_newtokenbuf(asn1_tokenbuf); | |
446 | } | |
447 | ||
448 | void asn1la_newtokenbuf(TokenBuf *tb) | |
449 | { | |
450 | if(!tb) | |
451 | FATAL_ERROR("asn1la_newtokenbuf(): tb is NULL"); | |
452 | asn1_tokenbuf_curr=tb; | |
453 | asn1_infile=asn1_tokenbuf_curr->get_filename(); | |
454 | yylineno=1; | |
455 | } | |
456 | ||
457 | void id_replace_underscores(char *s) | |
458 | { | |
459 | char *origid=0; | |
460 | char *p=s; | |
461 | while(*p!='\0') { | |
462 | if(*p=='_') { | |
463 | if(!origid) origid=mputstr(origid, s); | |
464 | *p='-'; | |
465 | } | |
466 | p++; | |
467 | } | |
468 | if(origid) { | |
469 | Location loc(asn1_infile, yylineno); | |
470 | loc.error("`%s' is not a valid ASN.1 identifier. Did you mean `%s'?", | |
471 | origid, s); | |
472 | Free(origid); | |
473 | } | |
474 | } | |
475 | ||
476 | void bhstring_remove_whitespaces(char *s) { | |
477 | char *p1, *p2; | |
478 | for(p1=p2=s; *p2; p2++) { | |
479 | switch(*p2) { | |
480 | case ' ': // whitespace, no newline chars | |
481 | case '\t': | |
482 | case 0x0A: // newline chars | |
483 | case 0x0B: | |
484 | case 0x0C: | |
485 | case 0x0D: | |
486 | break; | |
487 | default: | |
488 | *p1++=*p2; | |
489 | } // switch *p2 | |
490 | } // for | |
491 | *p1='\0'; | |
492 | } | |
493 | ||
494 | void cstring_remove_newlines(char *s) { | |
495 | /* also "" -> " */ | |
496 | char *p_r, *p_w, *p_b; | |
497 | enum {NO_WS, /**< no whitespace */ | |
498 | WS, /**< whitespace, but not newline */ | |
499 | NL /**< newline */ | |
500 | } state=NO_WS; | |
501 | /* | |
502 | p_r reads the string s; | |
503 | p_w writes into the string s; | |
504 | p_b is a bookmark for writing; shows the last non-whitespace character+1, | |
505 | if the state is WS; | |
506 | if state is NL, then the next whitespaces must be eaten up; | |
507 | */ | |
508 | for(p_w=p_b=p_r=s; *p_r; p_w++, p_r++) { | |
509 | switch(*p_r) { | |
510 | case ' ': // whitespace, no newline chars | |
511 | case '\t': | |
512 | if(state==NO_WS) {p_b=p_w; state=WS;} | |
513 | break; | |
514 | case 0x0A: // newline chars (LF,VT,FF,CR) | |
515 | case 0x0B: | |
516 | case 0x0C: | |
517 | case 0x0D: | |
518 | switch(state) { | |
519 | case NO_WS: | |
520 | p_b=p_w; | |
521 | /* no break */ | |
522 | case WS: | |
523 | case NL: | |
524 | state=NL; | |
525 | } // switch state | |
526 | break; | |
527 | default: // not whitespace chars | |
528 | if(state==NL) p_w=p_b; | |
529 | state=NO_WS; | |
530 | } // switch *p_r | |
531 | *p_w = *p_r; | |
532 | if (*p_r=='"' && *(p_r+1)=='"') { // On the first of two QUOTATION MARKs. | |
533 | p_w--; // Back up writing pos. The next " will overwrite this one. | |
534 | } | |
535 | } // for | |
536 | *p_w='\0'; | |
537 | } | |
538 | ||
539 | int asn1_yylex_my() | |
540 | { | |
541 | return asn1_tokenbuf_curr->lex(); | |
542 | } |