// SPDX-License-Identifier: GPL-2.0-or-later/* Simplified ASN.1 notation parser * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */ #include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <stdbool.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>#include <linux/asn1_ber_bytecode.h> enum token_type { DIRECTIVE_ABSENT, DIRECTIVE_ALL, DIRECTIVE_ANY, DIRECTIVE_APPLICATION, DIRECTIVE_AUTOMATIC, DIRECTIVE_BEGIN, DIRECTIVE_BIT, DIRECTIVE_BMPString, DIRECTIVE_BOOLEAN, DIRECTIVE_BY, DIRECTIVE_CHARACTER, DIRECTIVE_CHOICE, DIRECTIVE_CLASS, DIRECTIVE_COMPONENT, DIRECTIVE_COMPONENTS, DIRECTIVE_CONSTRAINED, DIRECTIVE_CONTAINING, DIRECTIVE_DEFAULT, DIRECTIVE_DEFINED, DIRECTIVE_DEFINITIONS, DIRECTIVE_EMBEDDED, DIRECTIVE_ENCODED, DIRECTIVE_ENCODING_CONTROL, DIRECTIVE_END, DIRECTIVE_ENUMERATED, DIRECTIVE_EXCEPT, DIRECTIVE_EXPLICIT, DIRECTIVE_EXPORTS, DIRECTIVE_EXTENSIBILITY, DIRECTIVE_EXTERNAL, DIRECTIVE_FALSE, DIRECTIVE_FROM, DIRECTIVE_GeneralString, DIRECTIVE_GeneralizedTime, DIRECTIVE_GraphicString, DIRECTIVE_IA5String, DIRECTIVE_IDENTIFIER, DIRECTIVE_IMPLICIT, DIRECTIVE_IMPLIED, DIRECTIVE_IMPORTS, DIRECTIVE_INCLUDES, DIRECTIVE_INSTANCE, DIRECTIVE_INSTRUCTIONS, DIRECTIVE_INTEGER, DIRECTIVE_INTERSECTION, DIRECTIVE_ISO646String, DIRECTIVE_MAX, DIRECTIVE_MIN, DIRECTIVE_MINUS_INFINITY, DIRECTIVE_NULL, DIRECTIVE_NumericString, DIRECTIVE_OBJECT, DIRECTIVE_OCTET, DIRECTIVE_OF, DIRECTIVE_OPTIONAL, DIRECTIVE_ObjectDescriptor, DIRECTIVE_PATTERN, DIRECTIVE_PDV, DIRECTIVE_PLUS_INFINITY, DIRECTIVE_PRESENT, DIRECTIVE_PRIVATE, DIRECTIVE_PrintableString, DIRECTIVE_REAL, DIRECTIVE_RELATIVE_OID, DIRECTIVE_SEQUENCE, DIRECTIVE_SET, DIRECTIVE_SIZE, DIRECTIVE_STRING, DIRECTIVE_SYNTAX, DIRECTIVE_T61String, DIRECTIVE_TAGS, DIRECTIVE_TRUE, DIRECTIVE_TeletexString, DIRECTIVE_UNION, DIRECTIVE_UNIQUE, DIRECTIVE_UNIVERSAL, DIRECTIVE_UTCTime, DIRECTIVE_UTF8String, DIRECTIVE_UniversalString, DIRECTIVE_VideotexString, DIRECTIVE_VisibleString, DIRECTIVE_WITH, NR__DIRECTIVES, TOKEN_ASSIGNMENT = NR__DIRECTIVES, TOKEN_OPEN_CURLY, TOKEN_CLOSE_CURLY, TOKEN_OPEN_SQUARE, TOKEN_CLOSE_SQUARE, TOKEN_OPEN_ACTION, TOKEN_CLOSE_ACTION, TOKEN_COMMA, TOKEN_NUMBER, TOKEN_TYPE_NAME, TOKEN_ELEMENT_NAME, NR__TOKENS}; static const unsigned char token_to_tag[NR__TOKENS] = { /* EOC goes first */ [DIRECTIVE_BOOLEAN] = ASN1_BOOL, [DIRECTIVE_INTEGER] = ASN1_INT, [DIRECTIVE_BIT] = ASN1_BTS, [DIRECTIVE_OCTET] = ASN1_OTS, [DIRECTIVE_NULL] = ASN1_NULL, [DIRECTIVE_OBJECT] = ASN1_OID, [DIRECTIVE_ObjectDescriptor] = ASN1_ODE, [DIRECTIVE_EXTERNAL] = ASN1_EXT, [DIRECTIVE_REAL] = ASN1_REAL, [DIRECTIVE_ENUMERATED] = ASN1_ENUM, [DIRECTIVE_EMBEDDED] = 0, [DIRECTIVE_UTF8String] = ASN1_UTF8STR, [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID, /* 14 */ /* 15 */ [DIRECTIVE_SEQUENCE] = ASN1_SEQ, [DIRECTIVE_SET] = ASN1_SET, [DIRECTIVE_NumericString] = ASN1_NUMSTR, [DIRECTIVE_PrintableString] = ASN1_PRNSTR, [DIRECTIVE_T61String] = ASN1_TEXSTR, [DIRECTIVE_TeletexString] = ASN1_TEXSTR, [DIRECTIVE_VideotexString] = ASN1_VIDSTR, [DIRECTIVE_IA5String] = ASN1_IA5STR, [DIRECTIVE_UTCTime] = ASN1_UNITIM, [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM, [DIRECTIVE_GraphicString] = ASN1_GRASTR, [DIRECTIVE_VisibleString] = ASN1_VISSTR, [DIRECTIVE_GeneralString] = ASN1_GENSTR, [DIRECTIVE_UniversalString] = ASN1_UNITIM, [DIRECTIVE_CHARACTER] = ASN1_CHRSTR, [DIRECTIVE_BMPString] = ASN1_BMPSTR,}; static const char asn1_classes[4][5] = { [ASN1_UNIV] = "UNIV", [ASN1_APPL] = "APPL", [ASN1_CONT] = "CONT", [ASN1_PRIV] = "PRIV"}; static const char asn1_methods[2][5] = { [ASN1_UNIV] = "PRIM", [ASN1_APPL] = "CONS"}; static const char *const asn1_universal_tags[32] = { "EOC", "BOOL", "INT", "BTS", "OTS", "NULL", "OID", "ODE", "EXT", "REAL", "ENUM", "EPDV", "UTF8STR", "RELOID", NULL, /* 14 */ NULL, /* 15 */ "SEQ", "SET", "NUMSTR", "PRNSTR", "TEXSTR", "VIDSTR", "IA5STR", "UNITIM", "GENTIM", "GRASTR", "VISSTR", "GENSTR", "UNISTR", "CHRSTR", "BMPSTR", NULL /* 31 */}; static const char *filename;static const char *grammar_name;static const char *outputname;static const char *headername; static const char *const directives[NR__DIRECTIVES] = {#define _(X) [DIRECTIVE_##X] = #X _(ABSENT), _(ALL), _(ANY), _(APPLICATION), _(AUTOMATIC), _(BEGIN), _(BIT), _(BMPString), _(BOOLEAN), _(BY), _(CHARACTER), _(CHOICE), _(CLASS), _(COMPONENT), _(COMPONENTS), _(CONSTRAINED), _(CONTAINING), _(DEFAULT), _(DEFINED), _(DEFINITIONS), _(EMBEDDED), _(ENCODED), [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL", _(END), _(ENUMERATED), _(EXCEPT), _(EXPLICIT), _(EXPORTS), _(EXTENSIBILITY), _(EXTERNAL), _(FALSE), _(FROM), _(GeneralString), _(GeneralizedTime), _(GraphicString), _(IA5String), _(IDENTIFIER), _(IMPLICIT), _(IMPLIED), _(IMPORTS), _(INCLUDES), _(INSTANCE), _(INSTRUCTIONS), _(INTEGER), _(INTERSECTION), _(ISO646String), _(MAX), _(MIN), [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY", [DIRECTIVE_NULL] = "NULL", _(NumericString), _(OBJECT), _(OCTET), _(OF), _(OPTIONAL), _(ObjectDescriptor), _(PATTERN), _(PDV), [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY", _(PRESENT), _(PRIVATE), _(PrintableString), _(REAL), [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID", _(SEQUENCE), _(SET), _(SIZE), _(STRING), _(SYNTAX), _(T61String), _(TAGS), _(TRUE), _(TeletexString), _(UNION), _(UNIQUE), _(UNIVERSAL), _(UTCTime), _(UTF8String), _(UniversalString), _(VideotexString), _(VisibleString), _(WITH)}; struct action { struct action *next; char *name; unsigned char index;}; static struct action *action_list;static unsigned nr_actions; struct token { unsigned short line; enum token_type token_type : 8; unsigned char size; struct action *action; char *content; struct type *type;}; static struct token *token_list;static unsigned nr_tokens;static bool verbose_opt;static bool debug_opt; #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0) static int directive_compare(const void *_key, const void *_pdir){ const struct token *token = _key; const char *const *pdir = _pdir, *dir = *pdir; size_t dlen, clen; int val; dlen = strlen(dir); clen = (dlen < token->size) ? dlen : token->size; //debug("cmp(%s,%s) = ", token->content, dir); val = memcmp(token->content, dir, clen); if (val != 0) { //debug("%d [cmp]\n", val); return val; } if (dlen == token->size) { //debug("0\n"); return 0; } //debug("%d\n", (int)dlen - (int)token->size); return dlen - token->size; /* shorter -> negative */} /* * Tokenise an ASN.1 grammar */static void tokenise(char *buffer, char *end){ struct token *tokens; char *line, *nl, *start, *p, *q; unsigned tix, lineno; /* Assume we're going to have half as many tokens as we have * characters */ token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); if (!tokens) { perror(NULL); exit(1); } tix = 0; lineno = 0; while (buffer < end) { /* First of all, break out a line */ lineno++; line = buffer; nl = memchr(line, '\n', end - buffer); if (!nl) { buffer = nl = end; } else { buffer = nl + 1; *nl = '\0'; } /* Remove "--" comments */ p = line; next_comment: while ((p = memchr(p, '-', nl - p))) { if (p[1] == '-') { /* Found a comment; see if there's a terminator */ q = p + 2; while ((q = memchr(q, '-', nl - q))) { if (q[1] == '-') { /* There is - excise the comment */ q += 2; memmove(p, q, nl - q); goto next_comment; } q++; } *p = '\0'; nl = p; break; } else { p++; } } p = line; while (p < nl) { /* Skip white space */ while (p < nl && isspace(*p)) *(p++) = 0; if (p >= nl) break; tokens[tix].line = lineno; start = p; /* Handle string tokens */ if (isalpha(*p)) { const char **dir; /* Can be a directive, type name or element * name. Find the end of the name. */ q = p + 1; while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) q++; tokens[tix].size = q - p; p = q; tokens[tix].content = malloc(tokens[tix].size + 1); if (!tokens[tix].content) { perror(NULL); exit(1); } memcpy(tokens[tix].content, start, tokens[tix].size); tokens[tix].content[tokens[tix].size] = 0; /* If it begins with a lowercase letter then * it's an element name */ if (islower(tokens[tix].content[0])) { tokens[tix++].token_type = TOKEN_ELEMENT_NAME; continue; } /* Otherwise we need to search the directive * table */ dir = bsearch(&tokens[tix], directives, sizeof(directives) / sizeof(directives[1]), sizeof(directives[1]), directive_compare); if (dir) { tokens[tix++].token_type = dir - directives; continue; } tokens[tix++].token_type = TOKEN_TYPE_NAME; continue; } /* Handle numbers */ if (isdigit(*p)) { /* Find the end of the number */ q = p + 1; while (q < nl && (isdigit(*q))) q++; tokens[tix].size = q - p; p = q; tokens[tix].content = malloc(tokens[tix].size + 1); if (!tokens[tix].content) { perror(NULL); exit(1); } memcpy(tokens[tix].content, start, tokens[tix].size); tokens[tix].content[tokens[tix].size] = 0; tokens[tix++].token_type = TOKEN_NUMBER; continue; } if (nl - p >= 3) { if (memcmp(p, "::=", 3) == 0) { p += 3; tokens[tix].size = 3; tokens[tix].content = "::="; tokens[tix++].token_type = TOKEN_ASSIGNMENT; continue; } } if (nl - p >= 2) { if (memcmp(p, "({", 2) == 0) { p += 2; tokens[tix].size = 2; tokens[tix].content = "({"; tokens[tix++].token_type = TOKEN_OPEN_ACTION; continue; } if (memcmp(p, "})", 2) == 0) { p += 2; tokens[tix].size = 2; tokens[tix].content = "})"; tokens[tix++].token_type = TOKEN_CLOSE_ACTION; continue; } } Lines 1–500 of 1611. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* Simplified ASN.1 notation parser * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <linux/asn1_ber_bytecode.h> enum token_type { DIRECTIVE_ABSENT, DIRECTIVE_ALL, DIRECTIVE_ANY, DIRECTIVE_APPLICATION, DIRECTIVE_AUTOMATIC, DIRECTIVE_BEGIN, DIRECTIVE_BIT, DIRECTIVE_BMPString, DIRECTIVE_BOOLEAN, DIRECTIVE_BY, DIRECTIVE_CHARACTER, DIRECTIVE_CHOICE, DIRECTIVE_CLASS, DIRECTIVE_COMPONENT, DIRECTIVE_COMPONENTS, DIRECTIVE_CONSTRAINED, DIRECTIVE_CONTAINING, DIRECTIVE_DEFAULT, DIRECTIVE_DEFINED, DIRECTIVE_DEFINITIONS, DIRECTIVE_EMBEDDED, DIRECTIVE_ENCODED, DIRECTIVE_ENCODING_CONTROL, DIRECTIVE_END, DIRECTIVE_ENUMERATED, DIRECTIVE_EXCEPT, DIRECTIVE_EXPLICIT, DIRECTIVE_EXPORTS, DIRECTIVE_EXTENSIBILITY, DIRECTIVE_EXTERNAL, DIRECTIVE_FALSE, DIRECTIVE_FROM, DIRECTIVE_GeneralString, DIRECTIVE_GeneralizedTime, DIRECTIVE_GraphicString, DIRECTIVE_IA5String, DIRECTIVE_IDENTIFIER, DIRECTIVE_IMPLICIT, DIRECTIVE_IMPLIED, DIRECTIVE_IMPORTS, DIRECTIVE_INCLUDES, DIRECTIVE_INSTANCE, DIRECTIVE_INSTRUCTIONS, DIRECTIVE_INTEGER, DIRECTIVE_INTERSECTION, DIRECTIVE_ISO646String, DIRECTIVE_MAX, DIRECTIVE_MIN, DIRECTIVE_MINUS_INFINITY, DIRECTIVE_NULL, DIRECTIVE_NumericString, DIRECTIVE_OBJECT, DIRECTIVE_OCTET, DIRECTIVE_OF, DIRECTIVE_OPTIONAL, DIRECTIVE_ObjectDescriptor, DIRECTIVE_PATTERN, DIRECTIVE_PDV, DIRECTIVE_PLUS_INFINITY, DIRECTIVE_PRESENT, DIRECTIVE_PRIVATE, DIRECTIVE_PrintableString, DIRECTIVE_REAL, DIRECTIVE_RELATIVE_OID, DIRECTIVE_SEQUENCE, DIRECTIVE_SET, DIRECTIVE_SIZE, DIRECTIVE_STRING, DIRECTIVE_SYNTAX, DIRECTIVE_T61String, DIRECTIVE_TAGS, DIRECTIVE_TRUE, DIRECTIVE_TeletexString, DIRECTIVE_UNION, DIRECTIVE_UNIQUE, DIRECTIVE_UNIVERSAL, DIRECTIVE_UTCTime, DIRECTIVE_UTF8String, DIRECTIVE_UniversalString, DIRECTIVE_VideotexString, DIRECTIVE_VisibleString, DIRECTIVE_WITH, NR__DIRECTIVES, TOKEN_ASSIGNMENT = NR__DIRECTIVES, TOKEN_OPEN_CURLY, TOKEN_CLOSE_CURLY, TOKEN_OPEN_SQUARE, TOKEN_CLOSE_SQUARE, TOKEN_OPEN_ACTION, TOKEN_CLOSE_ACTION, TOKEN_COMMA, TOKEN_NUMBER, TOKEN_TYPE_NAME, TOKEN_ELEMENT_NAME, NR__TOKENS }; static const unsigned char token_to_tag[NR__TOKENS] = { /* EOC goes first */ [DIRECTIVE_BOOLEAN] = ASN1_BOOL, [DIRECTIVE_INTEGER] = ASN1_INT, [DIRECTIVE_BIT] = ASN1_BTS, [DIRECTIVE_OCTET] = ASN1_OTS, [DIRECTIVE_NULL] = ASN1_NULL, [DIRECTIVE_OBJECT] = ASN1_OID, [DIRECTIVE_ObjectDescriptor] = ASN1_ODE, [DIRECTIVE_EXTERNAL] = ASN1_EXT, [DIRECTIVE_REAL] = ASN1_REAL, [DIRECTIVE_ENUMERATED] = ASN1_ENUM, [DIRECTIVE_EMBEDDED] = 0, [DIRECTIVE_UTF8String] = ASN1_UTF8STR, [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID, /* 14 */ /* 15 */ [DIRECTIVE_SEQUENCE] = ASN1_SEQ, [DIRECTIVE_SET] = ASN1_SET, [DIRECTIVE_NumericString] = ASN1_NUMSTR, [DIRECTIVE_PrintableString] = ASN1_PRNSTR, [DIRECTIVE_T61String] = ASN1_TEXSTR, [DIRECTIVE_TeletexString] = ASN1_TEXSTR, [DIRECTIVE_VideotexString] = ASN1_VIDSTR, [DIRECTIVE_IA5String] = ASN1_IA5STR, [DIRECTIVE_UTCTime] = ASN1_UNITIM, [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM, [DIRECTIVE_GraphicString] = ASN1_GRASTR, [DIRECTIVE_VisibleString] = ASN1_VISSTR, [DIRECTIVE_GeneralString] = ASN1_GENSTR, [DIRECTIVE_UniversalString] = ASN1_UNITIM, [DIRECTIVE_CHARACTER] = ASN1_CHRSTR, [DIRECTIVE_BMPString] = ASN1_BMPSTR, }; static const char asn1_classes[4][5] = { [ASN1_UNIV] = "UNIV", [ASN1_APPL] = "APPL", [ASN1_CONT] = "CONT", [ASN1_PRIV] = "PRIV" }; static const char asn1_methods[2][5] = { [ASN1_UNIV] = "PRIM", [ASN1_APPL] = "CONS" }; static const char *const asn1_universal_tags[32] = { "EOC", "BOOL", "INT", "BTS", "OTS", "NULL", "OID", "ODE", "EXT", "REAL", "ENUM", "EPDV", "UTF8STR", "RELOID", NULL, /* 14 */ NULL, /* 15 */ "SEQ", "SET", "NUMSTR", "PRNSTR", "TEXSTR", "VIDSTR", "IA5STR", "UNITIM", "GENTIM", "GRASTR", "VISSTR", "GENSTR", "UNISTR", "CHRSTR", "BMPSTR", NULL /* 31 */ }; static const char *filename; static const char *grammar_name; static const char *outputname; static const char *headername; static const char *const directives[NR__DIRECTIVES] = { #define _(X) [DIRECTIVE_##X] = #X _(ABSENT), _(ALL), _(ANY), _(APPLICATION), _(AUTOMATIC), _(BEGIN), _(BIT), _(BMPString), _(BOOLEAN), _(BY), _(CHARACTER), _(CHOICE), _(CLASS), _(COMPONENT), _(COMPONENTS), _(CONSTRAINED), _(CONTAINING), _(DEFAULT), _(DEFINED), _(DEFINITIONS), _(EMBEDDED), _(ENCODED), [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL", _(END), _(ENUMERATED), _(EXCEPT), _(EXPLICIT), _(EXPORTS), _(EXTENSIBILITY), _(EXTERNAL), _(FALSE), _(FROM), _(GeneralString), _(GeneralizedTime), _(GraphicString), _(IA5String), _(IDENTIFIER), _(IMPLICIT), _(IMPLIED), _(IMPORTS), _(INCLUDES), _(INSTANCE), _(INSTRUCTIONS), _(INTEGER), _(INTERSECTION), _(ISO646String), _(MAX), _(MIN), [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY", [DIRECTIVE_NULL] = "NULL", _(NumericString), _(OBJECT), _(OCTET), _(OF), _(OPTIONAL), _(ObjectDescriptor), _(PATTERN), _(PDV), [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY", _(PRESENT), _(PRIVATE), _(PrintableString), _(REAL), [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID", _(SEQUENCE), _(SET), _(SIZE), _(STRING), _(SYNTAX), _(T61String), _(TAGS), _(TRUE), _(TeletexString), _(UNION), _(UNIQUE), _(UNIVERSAL), _(UTCTime), _(UTF8String), _(UniversalString), _(VideotexString), _(VisibleString), _(WITH) }; struct action { struct action *next; char *name; unsigned char index; }; static struct action *action_list; static unsigned nr_actions; struct token { unsigned short line; enum token_type token_type : 8; unsigned char size; struct action *action; char *content; struct type *type; }; static struct token *token_list; static unsigned nr_tokens; static bool verbose_opt; static bool debug_opt; #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0) #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0) static int directive_compare(const void *_key, const void *_pdir) { const struct token *token = _key; const char *const *pdir = _pdir, *dir = *pdir; size_t dlen, clen; int val; dlen = strlen(dir); clen = (dlen < token->size) ? dlen : token->size; //debug("cmp(%s,%s) = ", token->content, dir); val = memcmp(token->content, dir, clen); if (val != 0) { //debug("%d [cmp]\n", val); return val; } if (dlen == token->size) { //debug("0\n"); return 0; } //debug("%d\n", (int)dlen - (int)token->size); return dlen - token->size; /* shorter -> negative */ } /* * Tokenise an ASN.1 grammar */ static void tokenise(char *buffer, char *end) { struct token *tokens; char *line, *nl, *start, *p, *q; unsigned tix, lineno; /* Assume we're going to have half as many tokens as we have * characters */ token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); if (!tokens) { perror(NULL); exit(1); } tix = 0; lineno = 0; while (buffer < end) { /* First of all, break out a line */ lineno++; line = buffer; nl = memchr(line, '\n', end - buffer); if (!nl) { buffer = nl = end; } else { buffer = nl + 1; *nl = '\0'; } /* Remove "--" comments */ p = line; next_comment: while ((p = memchr(p, '-', nl - p))) { if (p[1] == '-') { /* Found a comment; see if there's a terminator */ q = p + 2; while ((q = memchr(q, '-', nl - q))) { if (q[1] == '-') { /* There is - excise the comment */ q += 2; memmove(p, q, nl - q); goto next_comment; } q++; } *p = '\0'; nl = p; break; } else { p++; } } p = line; while (p < nl) { /* Skip white space */ while (p < nl && isspace(*p)) *(p++) = 0; if (p >= nl) break; tokens[tix].line = lineno; start = p; /* Handle string tokens */ if (isalpha(*p)) { const char **dir; /* Can be a directive, type name or element * name. Find the end of the name. */ q = p + 1; while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) q++; tokens[tix].size = q - p; p = q; tokens[tix].content = malloc(tokens[tix].size + 1); if (!tokens[tix].content) { perror(NULL); exit(1); } memcpy(tokens[tix].content, start, tokens[tix].size); tokens[tix].content[tokens[tix].size] = 0; /* If it begins with a lowercase letter then * it's an element name */ if (islower(tokens[tix].content[0])) { tokens[tix++].token_type = TOKEN_ELEMENT_NAME; continue; } /* Otherwise we need to search the directive * table */ dir = bsearch(&tokens[tix], directives, sizeof(directives) / sizeof(directives[1]), sizeof(directives[1]), directive_compare); if (dir) { tokens[tix++].token_type = dir - directives; continue; } tokens[tix++].token_type = TOKEN_TYPE_NAME; continue; } /* Handle numbers */ if (isdigit(*p)) { /* Find the end of the number */ q = p + 1; while (q < nl && (isdigit(*q))) q++; tokens[tix].size = q - p; p = q; tokens[tix].content = malloc(tokens[tix].size + 1); if (!tokens[tix].content) { perror(NULL); exit(1); } memcpy(tokens[tix].content, start, tokens[tix].size); tokens[tix].content[tokens[tix].size] = 0; tokens[tix++].token_type = TOKEN_NUMBER; continue; } if (nl - p >= 3) { if (memcmp(p, "::=", 3) == 0) { p += 3; tokens[tix].size = 3; tokens[tix].content = "::="; tokens[tix++].token_type = TOKEN_ASSIGNMENT; continue; } } if (nl - p >= 2) { if (memcmp(p, "({", 2) == 0) { p += 2; tokens[tix].size = 2; tokens[tix].content = "({"; tokens[tix++].token_type = TOKEN_OPEN_ACTION; continue; } if (memcmp(p, "})", 2) == 0) { p += 2; tokens[tix].size = 2; tokens[tix].content = "})"; tokens[tix++].token_type = TOKEN_CLOSE_ACTION; continue; } }