| %{ |
| |
| #include <string.h> |
| #include <errno.h> |
| #include <assert.h> |
| |
| #include "asn1parser.h" |
| #include "asn1p_y.h" |
| |
| int asn1p_lex(void); |
| void asn1p_lexer_hack_push_opaque_state(void); /* Used in .y */ |
| void asn1p_lexer_hack_enable_with_syntax(void); /* Used in .y */ |
| void asn1p_lexer_hack_push_encoding_control(void); /* Used in .y */ |
| |
| #define YY_FATAL_ERROR(msg) do { \ |
| fprintf(stderr, \ |
| "lexer error at line %d, " \ |
| "text \"%s\"\n", \ |
| yylineno, yytext); \ |
| exit(1); \ |
| } while(0) |
| |
| int asn1p_lexer_pedantic_1990 = 0; |
| int asn1p_lexer_types_year = 0; |
| int asn1p_lexer_constructs_year = 0; |
| int asn1p_lexer_extended_values = 0; |
| |
| int asn1p_as_pointer; |
| |
| static asn1c_integer_t _lex_atoi(const char *ptr); |
| static double _lex_atod(const char *ptr); |
| |
| /* |
| * Check that the type is defined in the year of the standard choosen. |
| */ |
| #define TYPE_LIFETIME(fyr, lyr) \ |
| (!asn1p_lexer_types_year \ |
| || (fyr && fyr <= asn1p_lexer_types_year) \ |
| || (lyr && lyr > asn1p_lexer_types_year)) |
| |
| /* |
| * Check the the construction (or concept, i.e. CLASS) is defined in |
| * a given year. |
| */ |
| #define CONSTRUCT_LIFETIME(fyr, lyr) \ |
| (!asn1p_lexer_constructs_year \ |
| || (fyr && fyr <= asn1p_lexer_constructs_year) \ |
| || (lyr && lyr > asn1p_lexer_constructs_year)) |
| |
| /* |
| * Append quoted string. |
| */ |
| #define QAPPEND(text, tlen) do { \ |
| char *prev_text = asn1p_lval.tv_opaque.buf; \ |
| int prev_len = asn1p_lval.tv_opaque.len; \ |
| char *p; \ |
| \ |
| p = malloc((tlen) + prev_len + 1); \ |
| if(p == NULL) return -1; \ |
| \ |
| if(prev_text) memcpy(p, prev_text, prev_len); \ |
| memcpy(p + prev_len, text, tlen); \ |
| p[prev_len + (tlen)] = '\0'; \ |
| \ |
| free(asn1p_lval.tv_opaque.buf); \ |
| asn1p_lval.tv_opaque.buf = p; \ |
| asn1p_lval.tv_opaque.len = (tlen) + prev_len; \ |
| } while(0) |
| |
| %} |
| |
| %option never-interactive |
| %option noinput |
| %option noyywrap stack |
| /* Performance penalty is OK */ |
| %option yylineno |
| /* Controlled from within application */ |
| %option debug |
| |
| %pointer |
| |
| %x dash_comment |
| %x idash_comment |
| %x cpp_comment |
| %x quoted |
| %x opaque |
| %x encoding_control |
| %x with_syntax |
| %x extended_values |
| |
| /* Newline */ |
| NL [\r\v\f\n] |
| /* White-space */ |
| WSP [\t\r\v\f\n ] |
| |
| %% |
| |
| <INITIAL>"\xef\xbb\xbf" return UTF8_BOM; |
| |
| -{3,}/[\r\n] /* Immediately terminated long comment */ |
| -{3,}/[^-\r\n] yy_push_state(idash_comment); /* Incorrect, but acceptable */ |
| <idash_comment>{ |
| -{3,} yy_pop_state(); /* Acceptable end of comment */ |
| } |
| |
| --<[ \t]*ASN1C.RepresentAsPointer[ \t]*>-- asn1p_as_pointer = 1; |
| |
| <extended_values>{ |
| "#BIT STRING" { |
| yy_pop_state(); |
| return TOK_ExtValue_BIT_STRING; |
| } |
| } |
| |
| <INITIAL,with_syntax>-- yy_push_state(dash_comment); |
| <dash_comment,idash_comment>{ |
| |
| {NL} yy_pop_state(); |
| |
| -- yy_pop_state(); /* End of comment */ |
| - /* Eat single dash */ |
| [^\r\v\f\n-]+ /* Eat */ |
| } |
| |
| <INITIAL,cpp_comment,with_syntax>"/*" yy_push_state(cpp_comment); |
| <cpp_comment>{ |
| [^*/<] /* Eat */ |
| "*/" yy_pop_state(); |
| . /* Eat */ |
| } |
| |
| |
| /* |
| * This is state is being set from corresponding .y module when |
| * higher-level data is necessary to make proper parsing of the |
| * underlying data. Thus, we enter the <opaque> state and save |
| * everything for later processing. |
| */ |
| <opaque>{ |
| |
| "{" { |
| yy_push_state(opaque); |
| asn1p_lval.tv_opaque.buf = strdup(yytext); |
| asn1p_lval.tv_opaque.len = yyleng; |
| return TOK_opaque; |
| } |
| |
| "}" { |
| yy_pop_state(); |
| asn1p_lval.tv_opaque.buf = strdup(yytext); |
| asn1p_lval.tv_opaque.len = yyleng; |
| return TOK_opaque; |
| } |
| |
| [^{}:=]+ { |
| asn1p_lval.tv_opaque.buf = strdup(yytext); |
| asn1p_lval.tv_opaque.len = yyleng; |
| return TOK_opaque; |
| } |
| |
| "::=" { |
| fprintf(stderr, |
| "ASN.1 Parser synchronization failure: " |
| "\"%s\" at line %d must not appear " |
| "inside value definition\n", |
| yytext, yylineno); |
| return -1; |
| } |
| |
| [:=] { |
| asn1p_lval.tv_opaque.buf = strdup(yytext); |
| asn1p_lval.tv_opaque.len = yyleng; |
| return TOK_opaque; |
| } |
| |
| } |
| |
| \"[^\"]* { |
| asn1p_lval.tv_opaque.buf = 0; |
| asn1p_lval.tv_opaque.len = 0; |
| QAPPEND(yytext+1, yyleng-1); |
| yy_push_state(quoted); |
| } |
| <quoted>{ |
| |
| \"\" { QAPPEND(yytext, yyleng-1); } /* Add a single quote */ |
| [^\"]+ { QAPPEND(yytext, yyleng); } |
| |
| \" { |
| yy_pop_state(); |
| /* Do not append last quote: |
| // QAPPEND(yytext, yyleng); */ |
| |
| if(asn1p_lexer_pedantic_1990 |
| && strchr(yytext, '\n')) { |
| fprintf(stderr, "%s: " |
| "Newlines are prohibited by ASN.1:1990\n", |
| asn1p_lval.tv_opaque.buf); |
| return -1; |
| } |
| |
| return TOK_cstring; |
| } |
| |
| } |
| |
| <encoding_control>{ |
| ENCODING-CONTROL { |
| const char *s = "ENCODING-CONTROL"; |
| const char *p = s + sizeof("ENCODING-CONTROL") - 2; |
| for(; p >= s; p--) unput(*p); |
| yy_pop_state(); |
| } |
| END unput('D'); unput('N'); unput('E'); yy_pop_state(); |
| [^{} \t\r\v\f\n]+ |
| [[:alnum:]]+ |
| . /* Eat everything else */ |
| "\n" |
| } |
| |
| '[0-9A-F \t\r\v\f\n]+'H { |
| /* " \t\r\n" weren't allowed in ASN.1:1990. */ |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_hstring; |
| } |
| |
| '[01 \t\r\v\f\n]+'B { |
| /* " \t\r\n" weren't allowed in ASN.1:1990. */ |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_bstring; |
| } |
| |
| |
| -[1-9][0-9]* { |
| asn1p_lval.a_int = _lex_atoi(yytext); |
| if(errno == ERANGE) |
| return -1; |
| return TOK_number_negative; |
| } |
| |
| [1-9][0-9]* { |
| asn1p_lval.a_int = _lex_atoi(yytext); |
| if(errno == ERANGE) |
| return -1; |
| return TOK_number; |
| } |
| |
| "0" { |
| asn1p_lval.a_int = _lex_atoi(yytext); |
| if(errno == ERANGE) |
| return -1; |
| return TOK_number; |
| } |
| |
| [-+]?[0-9]+[.]?([eE][-+]?)?[0-9]+ { |
| asn1p_lval.a_dbl = _lex_atod(yytext); |
| if(errno == ERANGE) |
| return -1; |
| return TOK_realnumber; |
| } |
| |
| ABSENT return TOK_ABSENT; |
| ALL return TOK_ALL; |
| ANY { |
| /* Appeared in 1990, removed in 1997 */ |
| if(TYPE_LIFETIME(1990, 1997)) |
| return TOK_ANY; |
| fprintf(stderr, "Keyword \"%s\" at line %d " |
| "is obsolete\n", yytext, yylineno); |
| REJECT; |
| } |
| APPLICATION return TOK_APPLICATION; |
| AUTOMATIC return TOK_AUTOMATIC; |
| BEGIN { |
| if(asn1p_lexer_extended_values) { |
| yy_push_state(extended_values); |
| } |
| return TOK_BEGIN; |
| } |
| BIT return TOK_BIT; |
| BMPString { |
| if(TYPE_LIFETIME(1994, 0)) |
| return TOK_BMPString; |
| REJECT; |
| } |
| BOOLEAN return TOK_BOOLEAN; |
| BY return TOK_BY; |
| CHARACTER return TOK_CHARACTER; |
| CHOICE return TOK_CHOICE; |
| CLASS return TOK_CLASS; |
| COMPONENT return TOK_COMPONENT; |
| COMPONENTS return TOK_COMPONENTS; |
| CONSTRAINED return TOK_CONSTRAINED; |
| CONTAINING return TOK_CONTAINING; |
| DEFAULT return TOK_DEFAULT; |
| DEFINED { |
| /* Appeared in 1990, removed in 1997 */ |
| if(TYPE_LIFETIME(1990, 1997)) |
| return TOK_DEFINED; |
| fprintf(stderr, "Keyword \"%s\" at line %d " |
| "is obsolete\n", yytext, yylineno); |
| /* Deprecated since */ |
| REJECT; |
| } |
| DEFINITIONS return TOK_DEFINITIONS; |
| EMBEDDED return TOK_EMBEDDED; |
| ENCODED return TOK_ENCODED; |
| ENCODING-CONTROL return TOK_ENCODING_CONTROL; |
| END { |
| if(YYSTATE == extended_values) { |
| yy_pop_state(); |
| } |
| return TOK_END; |
| } |
| ENUMERATED return TOK_ENUMERATED; |
| EXCEPT return TOK_EXCEPT; |
| EXPLICIT return TOK_EXPLICIT; |
| EXPORTS return TOK_EXPORTS; |
| EXTENSIBILITY return TOK_EXTENSIBILITY; |
| EXTERNAL return TOK_EXTERNAL; |
| FALSE return TOK_FALSE; |
| FROM return TOK_FROM; |
| GeneralizedTime return TOK_GeneralizedTime; |
| GeneralString return TOK_GeneralString; |
| GraphicString return TOK_GraphicString; |
| IA5String return TOK_IA5String; |
| IDENTIFIER return TOK_IDENTIFIER; |
| IMPLICIT return TOK_IMPLICIT; |
| IMPLIED return TOK_IMPLIED; |
| IMPORTS return TOK_IMPORTS; |
| INCLUDES return TOK_INCLUDES; |
| INSTANCE return TOK_INSTANCE; |
| INSTRUCTIONS return TOK_INSTRUCTIONS; |
| INTEGER return TOK_INTEGER; |
| INTERSECTION return TOK_INTERSECTION; |
| ISO646String return TOK_ISO646String; |
| MAX return TOK_MAX; |
| MIN return TOK_MIN; |
| MINUS-INFINITY return TOK_MINUS_INFINITY; |
| NULL return TOK_NULL; |
| NumericString return TOK_NumericString; |
| OBJECT return TOK_OBJECT; |
| ObjectDescriptor return TOK_ObjectDescriptor; |
| OCTET return TOK_OCTET; |
| OF return TOK_OF; |
| OPTIONAL return TOK_OPTIONAL; |
| PATTERN return TOK_PATTERN; |
| PDV return TOK_PDV; |
| PLUS-INFINITY return TOK_PLUS_INFINITY; |
| PRESENT return TOK_PRESENT; |
| PrintableString return TOK_PrintableString; |
| PRIVATE return TOK_PRIVATE; |
| REAL return TOK_REAL; |
| RELATIVE-OID return TOK_RELATIVE_OID; |
| SEQUENCE return TOK_SEQUENCE; |
| SET return TOK_SET; |
| SIZE return TOK_SIZE; |
| STRING return TOK_STRING; |
| SYNTAX return TOK_SYNTAX; |
| T61String return TOK_T61String; |
| TAGS return TOK_TAGS; |
| TeletexString return TOK_TeletexString; |
| TRUE return TOK_TRUE; |
| UNION return TOK_UNION; |
| UNIQUE return TOK_UNIQUE; |
| UNIVERSAL return TOK_UNIVERSAL; |
| UniversalString { |
| if(TYPE_LIFETIME(1994, 0)) |
| return TOK_UniversalString; |
| REJECT; |
| } |
| UTCTime return TOK_UTCTime; |
| UTF8String { |
| if(TYPE_LIFETIME(1994, 0)) |
| return TOK_UTF8String; |
| REJECT; |
| } |
| VideotexString return TOK_VideotexString; |
| VisibleString return TOK_VisibleString; |
| WITH return TOK_WITH; |
| |
| |
| <INITIAL,with_syntax>&[A-Z][A-Za-z0-9]*([-][A-Za-z0-9]+)* { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_typefieldreference; |
| } |
| |
| <INITIAL,with_syntax>&[a-z][a-zA-Z0-9]*([-][a-zA-Z0-9]+)* { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_valuefieldreference; |
| } |
| |
| |
| [a-z][a-zA-Z0-9]*([-][a-zA-Z0-9]+)* { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_identifier; |
| } |
| |
| /* |
| * objectclassreference |
| */ |
| <INITIAL,extended_values>[A-Z][A-Z0-9]*([-][A-Z0-9]+)* { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_capitalreference; |
| } |
| |
| /* |
| * typereference, modulereference |
| * NOTE: TOK_objectclassreference must be combined |
| * with this token to produce true typereference. |
| */ |
| [A-Z][A-Za-z0-9]*([-][A-Za-z0-9]+)* { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_typereference; |
| } |
| |
| <INITIAL,extended_values>"::=" return TOK_PPEQ; |
| |
| "..." return TOK_ThreeDots; |
| ".." return TOK_TwoDots; |
| |
| <with_syntax>{ |
| |
| [A-Z][A-Za-z0-9]*([-][A-Za-z0-9]+)* { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_Literal; |
| } |
| |
| "," { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_Literal; |
| } |
| |
| "{" { |
| yy_push_state(with_syntax); |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_Literal; |
| } |
| |
| "[" return '['; |
| "]" return ']'; |
| |
| {WSP}+ { |
| asn1p_lval.tv_opaque.buf = strdup(yytext); |
| asn1p_lval.tv_opaque.len = yyleng; |
| return TOK_whitespace; |
| } |
| |
| "}" { |
| yy_pop_state(); |
| if(YYSTATE == with_syntax) { |
| asn1p_lval.tv_str = strdup(yytext); |
| return TOK_Literal; |
| } else { |
| return '}'; |
| } |
| } |
| |
| } |
| |
| |
| <INITIAL,extended_values>{WSP}+ /* Ignore whitespace */ |
| |
| |
| [{][\t\r\v\f\n ]*[0-7][,][\t\r\v\f\n ]*[0-9]+[\t\r\v\f\n ]*[}] { |
| asn1c_integer_t v1 = -1, v2 = -1; |
| char *p; |
| for(p = yytext; *p; p++) |
| if(*p >= '0' && *p <= '9') |
| { v1 = _lex_atoi(p); break; } |
| while(*p >= '0' && *p <= '9') p++; /* Skip digits */ |
| for(; *p; p++) if(*p >= '0' && *p <= '9') |
| { v2 = _lex_atoi(p); break; } |
| if(v1 < 0 || v1 > 7) { |
| fprintf(stderr, "%s at line %d: X.680:2003, #37.14 " |
| "mandates 0..7 range for Tuple's TableColumn\n", |
| yytext, yylineno); |
| return -1; |
| } |
| if(v2 < 0 || v2 > 15) { |
| fprintf(stderr, "%s at line %d: X.680:2003, #37.14 " |
| "mandates 0..15 range for Tuple's TableRow\n", |
| yytext, yylineno); |
| return -1; |
| } |
| asn1p_lval.a_int = (v1 << 4) + v2; |
| return TOK_tuple; |
| } |
| |
| [{][\t\r\v\f\n ]*[0-9]+[,][\t\r\v\f\n ]*[0-9]+[,][\t\r\v\f\n ]*[0-9]+[,][\t\r\v\f\n ]*[0-9]+[\t\r\v\f\n ]*[}] { |
| asn1c_integer_t v1 = -1, v2 = -1, v3 = -1, v4 = -1; |
| char *p; |
| for(p = yytext; *p; p++) |
| if(*p >= '0' && *p <= '9') |
| { v1 = _lex_atoi(p); break; } |
| while(*p >= '0' && *p <= '9') p++; /* Skip digits */ |
| for(; *p; p++) if(*p >= '0' && *p <= '9') |
| { v2 = _lex_atoi(p); break; } |
| while(*p >= '0' && *p <= '9') p++; |
| for(; *p; p++) if(*p >= '0' && *p <= '9') |
| { v3 = _lex_atoi(p); break; } |
| while(*p >= '0' && *p <= '9') p++; |
| for(; *p; p++) if(*p >= '0' && *p <= '9') |
| { v4 = _lex_atoi(p); break; } |
| if(v1 < 0 || v1 > 127) { |
| fprintf(stderr, "%s at line %d: X.680:2003, #37.12 " |
| "mandates 0..127 range for Quadruple's Group\n", |
| yytext, yylineno); |
| return -1; |
| } |
| if(v2 < 0 || v2 > 255) { |
| fprintf(stderr, "%s at line %d: X.680:2003, #37.12 " |
| "mandates 0..255 range for Quadruple's Plane\n", |
| yytext, yylineno); |
| return -1; |
| } |
| if(v3 < 0 || v3 > 255) { |
| fprintf(stderr, "%s at line %d: X.680:2003, #37.12 " |
| "mandates 0..255 range for Quadruple's Row\n", |
| yytext, yylineno); |
| return -1; |
| } |
| if(v4 < 0 || v4 > 255) { |
| fprintf(stderr, "%s at line %d: X.680:2003, #37.12 " |
| "mandates 0..255 range for Quadruple's Cell\n", |
| yytext, yylineno); |
| return -1; |
| } |
| asn1p_lval.a_int = (v1 << 24) | (v2 << 16) | (v3 << 8) | v4; |
| return TOK_quadruple; |
| } |
| |
| |
| "[[" return TOK_VBracketLeft; |
| "]]" return TOK_VBracketRight; |
| |
| [(){},;:|!.&@\[\]^] return yytext[0]; |
| |
| [^A-Za-z0-9:=,{}<.@()[]'\"|&^*;!-] { |
| if(TYPE_LIFETIME(1994, 0)) |
| fprintf(stderr, "ERROR: "); |
| fprintf(stderr, |
| "Symbol '%c' at line %d is prohibited " |
| "by ASN.1:1994 and ASN.1:1997\n", |
| yytext[0], yylineno); |
| if(TYPE_LIFETIME(1994, 0)) |
| return -1; |
| } |
| |
| <*>. { |
| fprintf(stderr, |
| "Unexpected token at line %d: \"%s\"\n", |
| yylineno, yytext); |
| while(YYSTATE != INITIAL) |
| yy_pop_state(); |
| if(0) { |
| yy_top_state(); /* Just to use this function. */ |
| yy_fatal_error("Parse error"); |
| } |
| return -1; |
| } |
| |
| <*><<EOF>> { |
| while(YYSTATE != INITIAL) |
| yy_pop_state(); |
| yyterminate(); |
| } |
| |
| |
| %% |
| |
| /* |
| * Very dirty but wonderful hack allowing to rule states from within .y file. |
| */ |
| void asn1p_lexer_hack_push_opaque_state() { yy_push_state(opaque); } |
| |
| /* |
| * Another hack which disables recognizing some tokens when inside WITH SYNTAX. |
| */ |
| void asn1p_lexer_hack_enable_with_syntax() { yy_push_state(with_syntax); } |
| |
| /* Yet another */ |
| void asn1p_lexer_hack_push_encoding_control() { |
| yy_push_state(encoding_control); |
| } |
| |
| static asn1c_integer_t |
| _lex_atoi(const char *ptr) { |
| asn1c_integer_t value; |
| if(asn1p_atoi(ptr, &value)) { |
| fprintf(stderr, |
| "Value \"%s\" at line %d is too large " |
| "for this compiler! Please contact the asn1c author.\n", |
| ptr, yylineno); |
| errno = ERANGE; |
| } |
| return value; |
| } |
| |
| static double |
| _lex_atod(const char *ptr) { |
| double value; |
| errno = 0; |
| value = strtod(ptr, 0); |
| if(errno) { |
| fprintf(stderr, |
| "Value \"%s\" at line %d is outside of `double` range " |
| "in this compiler! Please contact the asn1c author.\n", |
| ptr, yylineno); |
| errno = ERANGE; |
| } |
| return value; |
| } |
| |