%{ #include #include #include #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_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 /* Newline */ NL [\r\v\f\n] /* White-space */ WSP [\t\r\v\f\n ] %% -{3,}/[\r\n] /* Immediately terminated long comment */ -{3,}/[^-\r\n] yy_push_state(idash_comment); /* Incorrect, but acceptable */ { -{3,} yy_pop_state(); /* Acceptable end of comment */ } --<[ \t]*ASN1C.RepresentAsPointer[ \t]*>-- asn1p_as_pointer = 1; -- yy_push_state(dash_comment); { {NL} yy_pop_state(); -- yy_pop_state(); /* End of comment */ - /* Eat single dash */ [^\r\v\f\n-]+ /* Eat */ } "/*" yy_push_state(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 state and save * everything for later processing. */ { "{" { 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 syncronization 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); } { \"\" { 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 { 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 = 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 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 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; &[A-Z][A-Za-z0-9]*([-][A-Za-z0-9]+)* { asn1p_lval.tv_str = strdup(yytext); return TOK_typefieldreference; } &[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 */ [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; } "::=" return TOK_PPEQ; "..." return TOK_ThreeDots; ".." return TOK_TwoDots; { [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 '}'; } } } {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 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; } <*><> { 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; }