diff options
Diffstat (limited to '')
-rw-r--r-- | src/mds-kbdc/make-tree.c | 1705 |
1 files changed, 829 insertions, 876 deletions
diff --git a/src/mds-kbdc/make-tree.c b/src/mds-kbdc/make-tree.c index 1b5e8a5..f5bdf55 100644 --- a/src/mds-kbdc/make-tree.c +++ b/src/mds-kbdc/make-tree.c @@ -31,7 +31,7 @@ #ifndef DEBUG # define DEBUG_PROC(statements) #else -# define DEBUG_PROC(statements) statements +# define DEBUG_PROC(statements) statements #endif @@ -40,16 +40,14 @@ * as a compiler debugging feature and should be used from * inside `DEBUG_PROC` */ -#define PRINT_STACK \ - do \ - { \ - size_t i = stack_ptr; \ - fprintf(stderr, "stack {\n"); \ - while (i--) \ - fprintf(stderr, " %s\n", keyword_stack[i]); \ - fprintf(stderr, "}\n"); \ - } \ - while (0) +#define PRINT_STACK\ + do {\ + size_t i = stack_ptr;\ + fprintf(stderr, "stack {\n");\ + while (i--)\ + fprintf(stderr, " %s\n", keyword_stack[i]);\ + fprintf(stderr, "}\n");\ + } while (0) /** @@ -60,8 +58,8 @@ * @param UPPER:¿T? The upper bound, inclusive * @return :int 1 if `LOWER` ≤ `VALUE` ≤ `UPPER`, otherwise 0 */ -#define in_range(LOWER, VALUE, UPPER) \ - (((LOWER) <= (VALUE)) && ((VALUE) <= (UPPER))) +#define in_range(LOWER, VALUE, UPPER)\ + ((LOWER) <= (VALUE) && (VALUE) <= (UPPER)) /** @@ -70,23 +68,23 @@ * @param C:char The character * @return :int Zero if `C` is a valid callable name character or a forward slash, otherwise 0 */ -#define is_name_char(C) \ - (in_range('a', C, 'z') || in_range('A', C, 'Z') || strchr("0123456789_/", C)) +#define is_name_char(C)\ + (in_range('a', C, 'z') || in_range('A', C, 'Z') || strchr("0123456789_/", C)) /** * Pointer to the beginning of the current line */ -#define LINE \ - (result->source_code->lines[line_i]) +#define LINE\ + (result->source_code->lines[line_i]) /** * Update the tip of the stack to point to the address * of the current stack's tip's `next`-member */ -#define NEXT \ - tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next) +#define NEXT\ + tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next) /** @@ -97,9 +95,9 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, ERROR_IS_IN_FILE, line_i, \ - (size_t)(line - LINE), (size_t)(end - LINE), 1, __VA_ARGS__) +#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, ERROR_IS_IN_FILE, line_i,\ + (size_t)(line - LINE), (size_t)(end - LINE), 1, __VA_ARGS__) /** @@ -108,13 +106,13 @@ * @param LOWERCASE:identifier The keyword, for the node type, in lower case * @param UPPERCASE:identifier The keyword, for the node type, in upper case */ -#define NEW_NODE(LOWERCASE, UPPERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* node; \ - fail_if (xcalloc(node, 1, mds_kbdc_tree_##LOWERCASE##_t)); \ - node->type = MDS_KBDC_TREE_TYPE_##UPPERCASE; \ - node->loc_line = line_i; \ - node->loc_start = (size_t)(line - LINE); \ - node->loc_end = (size_t)(end - LINE) +#define NEW_NODE(LOWERCASE, UPPERCASE)\ + mds_kbdc_tree_##LOWERCASE##_t *node;\ + fail_if (xcalloc(node, 1, mds_kbdc_tree_##LOWERCASE##_t));\ + node->type = MDS_KBDC_TREE_TYPE_##UPPERCASE;\ + node->loc_line = line_i;\ + node->loc_start = (size_t)(line - LINE);\ + node->loc_end = (size_t)(end - LINE) /** @@ -123,13 +121,13 @@ * @param LOWERCASE:identifier The keyword, for the node type, in lower case * @param UPPERCASE:identifier The keyword, for the node type, in upper case */ -#define NEW_SUBNODE(LOWERCASE, UPPERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* subnode; \ - fail_if (xcalloc(subnode, 1, mds_kbdc_tree_##LOWERCASE##_t)); \ - subnode->type = MDS_KBDC_TREE_TYPE_##UPPERCASE; \ - subnode->loc_line = line_i; \ - subnode->loc_start = (size_t)(line - LINE); \ - subnode->loc_end = (size_t)(end - LINE) +#define NEW_SUBNODE(LOWERCASE, UPPERCASE)\ + mds_kbdc_tree_##LOWERCASE##_t *subnode;\ + fail_if (xcalloc(subnode, 1, mds_kbdc_tree_##LOWERCASE##_t));\ + subnode->type = MDS_KBDC_TREE_TYPE_##UPPERCASE;\ + subnode->loc_line = line_i;\ + subnode->loc_start = (size_t)(line - LINE);\ + subnode->loc_end = (size_t)(end - LINE) /** @@ -142,10 +140,10 @@ * * @param KEYWORD:const char* The keyword for the current node's type */ -#define BRANCH(KEYWORD) \ - (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node, \ - tree_stack[stack_ptr + 1] = &(node->inner), \ - keyword_stack[stack_ptr++] = KEYWORD) +#define BRANCH(KEYWORD)\ + (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t *)node,\ + tree_stack[stack_ptr + 1] = &(node->inner),\ + keyword_stack[stack_ptr++] = KEYWORD) /** @@ -156,9 +154,9 @@ * This is what should be done when a leaf node has been * created and should be added to the result tree */ -#define LEAF \ - (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node, \ - NEXT) +#define LEAF\ + (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node,\ + NEXT) /** @@ -166,9 +164,9 @@ * * @param var:const char* The variable */ -#define SKIP_SPACES(var) \ - while (*var && (*var == ' ')) \ - var++ +#define SKIP_SPACES(var)\ + while (*var && *var == ' ')\ + var++ /** @@ -176,8 +174,8 @@ * * @param KEYWORD:const char* The keyword */ -#define NO_PARAMETERS(KEYWORD) \ - fail_if (no_parameters(KEYWORD)) +#define NO_PARAMETERS(KEYWORD)\ + fail_if (no_parameters(KEYWORD)) /** @@ -187,18 +185,18 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define NAMES_1(var) \ - fail_if (names_1(&(node->var))) +#define NAMES_1(var)\ + fail_if (names_1(&node->var)) /** * Suppress the next `line = STREND(line)` */ -#define NO_JUMP \ - (*end = prev_end_char, \ - end = line, \ - prev_end_char = *end, \ - *end = '\0') +#define NO_JUMP\ + (*end = prev_end_char,\ + end = line,\ + prev_end_char = *end,\ + *end = '\0') /** @@ -206,8 +204,8 @@ * * @param c:char The character */ -#define IS_END(c) \ - strchr(" >}])", c) +#define IS_END(c)\ + strchr(" >}])", c) /** @@ -217,31 +215,28 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define CHARS(var) \ - fail_if (chars(&(node->var))) +#define CHARS(var)\ + fail_if (chars(&node->var)) /** * Test that there are no more parameters */ -#define END \ - do \ - { \ - SKIP_SPACES(line); \ - if (*line) \ - { \ - NEW_ERROR(1, ERROR, "too many parameters"); \ - error->end = strlen(LINE); \ - } \ - } \ - while (0) +#define END\ + do {\ + SKIP_SPACES(line);\ + if (*line) {\ + NEW_ERROR(1, ERROR, "too many parameters");\ + error->end = strlen(LINE);\ + }\ + } while (0) /** * Test that the next parameter is in quotes */ -#define QUOTES \ - fail_if (quotes()) +#define QUOTES\ + fail_if (quotes()) /** @@ -251,14 +246,12 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define QUOTES_1(var) \ - do \ - { \ - QUOTES; \ - CHARS(var); \ - END; \ - } \ - while (0) +#define QUOTES_1(var)\ + do {\ + QUOTES;\ + CHARS(var);\ + END;\ + } while (0) /** @@ -266,8 +259,8 @@ * * @param KEYWORD:const char* The keyword */ -#define TEST_FOR_KEYWORD(KEYWORD) \ - fail_if (test_for_keyword(KEYWORD)) +#define TEST_FOR_KEYWORD(KEYWORD)\ + fail_if (test_for_keyword(KEYWORD)) /** @@ -277,8 +270,8 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define KEYS(var) \ - fail_if (keys(&(node->var))) +#define KEYS(var)\ + fail_if (keys(&node->var)) /** @@ -288,8 +281,8 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define PURE_KEYS(var) \ - fail_if (pure_keys(&(node->var))) +#define PURE_KEYS(var)\ + fail_if (pure_keys(&node->var)) @@ -299,23 +292,21 @@ * @param mapseq:int Whether this is a mapping sequence, otherwise * it is treated as macro call arguments */ -#define SEQUENCE(mapseq) \ - do /* for(;;) */ \ - { \ - *end = prev_end_char; \ - SKIP_SPACES(line); \ - if ((*line == '\0') || (*line == (mapseq ? ':' : ')'))) \ - break; \ - fail_if (sequence(mapseq, stack_orig)); \ - } \ - while (1) +#define SEQUENCE(mapseq)\ + do /* for(;;) */ {\ + *end = prev_end_char;\ + SKIP_SPACES(line);\ + if (!*line || *line == (mapseq ? ':' : ')'))\ + break;\ + fail_if (sequence(mapseq, stack_orig));\ + } while (1) /** * Check that the scopes created in `SEQUENCE` has all been popped */ -#define SEQUENCE_FULLY_POPPED \ - fail_if (sequence_fully_popped(stack_orig)) +#define SEQUENCE_FULLY_POPPED\ + fail_if (sequence_fully_popped(stack_orig)) /** @@ -325,14 +316,12 @@ * @param UPPERCASE:identifier The keyword, for the node type, in upper case * @param PARSE:expression Statement, without final semicolon, to retrieve members */ -#define MAKE_LEAF(LOWERCASE, UPPERCASE, PARSE) \ - do \ - { \ - NEW_NODE(LOWERCASE, UPPERCASE); \ - PARSE; \ - LEAF; \ - } \ - while (0) +#define MAKE_LEAF(LOWERCASE, UPPERCASE, PARSE)\ + do {\ + NEW_NODE(LOWERCASE, UPPERCASE);\ + PARSE;\ + LEAF;\ + } while (0) /** @@ -342,26 +331,24 @@ * @param UPPERCASE:identifier The keyword, for the node type, in upper case * @param PARSE:expression Statement, without final semicolon, to retrieve members */ -#define MAKE_BRANCH(LOWERCASE, UPPERCASE, PARSE) \ - do \ - { \ - NEW_NODE(LOWERCASE, UPPERCASE); \ - PARSE; \ - BRANCH(#LOWERCASE); \ - } \ - while (0) +#define MAKE_BRANCH(LOWERCASE, UPPERCASE, PARSE)\ + do {\ + NEW_NODE(LOWERCASE, UPPERCASE);\ + PARSE;\ + BRANCH(#LOWERCASE);\ + } while (0) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * Output parameter for the parsing result */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * The head of the parsing-stack @@ -371,12 +358,12 @@ static size_t stack_ptr; /** * The keyword portion of the parsing-stack */ -static const char** restrict keyword_stack; +static const char **restrict keyword_stack; /** * The tree portion of the parsing-stack */ -static mds_kbdc_tree_t*** restrict tree_stack; +static mds_kbdc_tree_t ***restrict tree_stack; /** * The index of the currently parsed line @@ -392,12 +379,12 @@ static int in_array; * The beginning of what has not get been parsed * on the current line */ -static char* line = NULL; +static char *line = NULL; /** * The end of what has been parsed on the current line */ -static char* end = NULL; +static char *end = NULL; /** * The previous value of `*end` @@ -408,7 +395,7 @@ static char prev_end_char; * Pointer to the first non-whitespace character * on the current line */ -static char* original; +static char *original; /** * Whether it has been identified that the @@ -427,40 +414,39 @@ static int too_few; * @param filename The filename of the parsed file * @return The value the caller should return, or 1 if the caller should not return, -1 on error */ -static int get_pathname(const char* restrict filename) +static int +get_pathname(const char *restrict filename) { - char* cwd = NULL; - int saved_errno; - - /* Get a non-relative pathname for the file, relative filenames - * can be misleading as the program can have changed working - * directory to be able to resolve filenames. */ - result->pathname = abspath(filename); - if (result->pathname == NULL) - { - fail_if (errno != ENOENT); - saved_errno = errno; - fail_if (cwd = curpath(), cwd == NULL); - fail_if (xstrdup(result->pathname, filename)); - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); - free(cwd); - return 0; - } - - /* Check that the file exists and can be read. */ - if (access(result->pathname, R_OK) < 0) - { - saved_errno = errno; - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 0, NULL); - fail_if (xstrdup(error->description, strerror(saved_errno))); - return 0; - } - - return 1; - fail: - saved_errno = errno; - free(cwd); - return errno = saved_errno, -1; + char *cwd = NULL; + int saved_errno; + + /* Get a non-relative pathname for the file, relative filenames + * can be misleading as the program can have changed working + * directory to be able to resolve filenames. */ + result->pathname = abspath(filename); + if (!result->pathname) { + fail_if (errno != ENOENT); + saved_errno = errno; + fail_if (!(cwd = curpath())); + fail_if (xstrdup(result->pathname, filename)); + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); + free(cwd); + return 0; + } + + /* Check that the file exists and can be read. */ + if (access(result->pathname, R_OK) < 0) { + saved_errno = errno; + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 0, NULL); + fail_if (xstrdup(error->description, strerror(saved_errno))); + return 0; + } + + return 1; +fail: + saved_errno = errno; + free(cwd); + return errno = saved_errno, -1; } @@ -469,25 +455,25 @@ static int get_pathname(const char* restrict filename) * * @return Zero on success, -1 on error */ -static int allocate_stacks(void) +static int +allocate_stacks(void) { - size_t max_line_length = 0, cur_line_length, line_n; - - /* The maximum line-length is needed because lines can have there own stacking, - * like sequence mapping lines, additionally, let statements can have one array. */ - for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) - { - cur_line_length = strlen(LINE); - if (max_line_length < cur_line_length) - max_line_length = cur_line_length; - } - - fail_if (xmalloc(keyword_stack, line_n + max_line_length, const char*)); - fail_if (xmalloc(tree_stack, line_n + max_line_length + 1, mds_kbdc_tree_t**)); - - return 0; - fail: - return -1; + size_t max_line_length = 0, cur_line_length, line_n; + + /* The maximum line-length is needed because lines can have there own stacking, + * like sequence mapping lines, additionally, let statements can have one array. */ + for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) { + cur_line_length = strlen(LINE); + if (max_line_length < cur_line_length) + max_line_length = cur_line_length; + } + + fail_if (xmalloc(keyword_stack, line_n + max_line_length, const char*)); + fail_if (xmalloc(tree_stack, line_n + max_line_length + 1, mds_kbdc_tree_t**)); + + return 0; +fail: + return -1; } @@ -496,14 +482,15 @@ static int allocate_stacks(void) * * @return Zero on success, -1 on error */ -static int read_source_code(void) +static int +read_source_code(void) { - /* Read the file and simplify it a bit. */ - fail_if (read_source_lines(result->pathname, result->source_code) < 0); - - return 0; - fail: - return -1; + /* Read the file and simplify it a bit. */ + fail_if (read_source_lines(result->pathname, result->source_code) < 0); + + return 0; +fail: + return -1; } @@ -517,34 +504,32 @@ static int read_source_code(void) * * @return Zero on success, -1 on error */ -static int check_for_premature_end_of_file(void) +static int +check_for_premature_end_of_file(void) { - /* Check that all scopes have been popped. */ - if (stack_ptr) - { - while (stack_ptr && keyword_stack[stack_ptr - 1] == NULL) - stack_ptr--; - if (stack_ptr) - { - NEW_ERROR(0, ERROR, "premature end of file"); - while (stack_ptr--) - { - if (keyword_stack[stack_ptr] == NULL) - continue; - line_i = tree_stack[stack_ptr][0]->loc_line; - line = LINE + tree_stack[stack_ptr][0]->loc_start; - end = LINE + tree_stack[stack_ptr][0]->loc_end; - if (!strcmp(keyword_stack[stack_ptr], "}")) - NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); - else - NEW_ERROR(1, NOTE, "missing associated ‘end %s’", keyword_stack[stack_ptr]); - } + /* Check that all scopes have been popped. */ + if (stack_ptr) { + while (stack_ptr && !keyword_stack[stack_ptr - 1]) + stack_ptr--; + if (stack_ptr) { + NEW_ERROR(0, ERROR, "premature end of file"); + while (stack_ptr--) { + if (!keyword_stack[stack_ptr]) + continue; + line_i = tree_stack[stack_ptr][0]->loc_line; + line = LINE + tree_stack[stack_ptr][0]->loc_start; + end = LINE + tree_stack[stack_ptr][0]->loc_end; + if (!strcmp(keyword_stack[stack_ptr], "}")) + NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); + else + NEW_ERROR(1, NOTE, "missing associated ‘end %s’", keyword_stack[stack_ptr]); + } + } } - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -555,16 +540,16 @@ static int check_for_premature_end_of_file(void) * * @return Zero on success, -1 on error */ -static int check_whether_file_is_empty(void) +static int +check_whether_file_is_empty(void) { - /* Warn about empty files. */ - if (result->tree == NULL) - if (result->errors_ptr == 0) - NEW_ERROR(0, WARNING, "file is empty"); - - return 0; - fail: - return -1; + /* Warn about empty files. */ + if (!result->tree && !result->errors_ptr) + NEW_ERROR(0, WARNING, "file is empty"); + + return 0; +fail: + return -1; } @@ -578,20 +563,20 @@ static int check_whether_file_is_empty(void) * @param keyword The keyword * @return Zero on success, -1 on error */ -static int no_parameters(const char* restrict keyword) +static int +no_parameters(const char *restrict keyword) { - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line) - { - end = STREND(line); - NEW_ERROR(1, ERROR, "extra token after ‘%s’", keyword); - } - - return 0; - fail: - return -1; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (*line) { + end = STREND(line); + NEW_ERROR(1, ERROR, "extra token after ‘%s’", keyword); + } + + return 0; +fail: + return -1; } @@ -604,55 +589,51 @@ static int no_parameters(const char* restrict keyword) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int names_1(char** restrict var) +static int +names_1(char **restrict var) { - char* name_end; - char* test; - int stray_char = 0; - char* end_end; - - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "a name is expected"); - } - else - { - name_end = line; - while (*name_end && is_name_char(*name_end)) - name_end++; - if (*name_end && (*name_end != ' ')) - { - end_end = name_end + 1; - while ((*end_end & 0xC0) == 0x80) - end_end++; - prev_end_char = *end_end, *end_end = '\0'; - NEW_ERROR(1, ERROR, "stray ‘%s’ character", name_end); - error->start = (size_t)(name_end - LINE); - error->end = (size_t)(end_end - LINE); - *end_end = prev_end_char; - stray_char = 1; + char *name_end; + char *test; + int stray_char = 0; + char *end_end; + + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "a name is expected"); + } else { + name_end = line; + while (*name_end && is_name_char(*name_end)) + name_end++; + if (*name_end && (*name_end != ' ')) { + end_end = name_end + 1; + while ((*end_end & 0xC0) == 0x80) + end_end++; + prev_end_char = *end_end, *end_end = '\0'; + NEW_ERROR(1, ERROR, "stray ‘%s’ character", name_end); + error->start = (size_t)(name_end - LINE); + error->end = (size_t)(end_end - LINE); + *end_end = prev_end_char; + stray_char = 1; + } + test = name_end; + SKIP_SPACES(test); + if (*test && !stray_char) { + NEW_ERROR(1, ERROR, "too many parameters"); + error->start = (size_t)(test - LINE); + error->end = strlen(LINE); + } + end = name_end; + prev_end_char = *end; + *end = '\0'; + fail_if (xstrdup(*var, line)); } - test = name_end; - SKIP_SPACES(test); - if (*test && !stray_char) - { - NEW_ERROR(1, ERROR, "too many parameters"); - error->start = (size_t)(test - LINE); - error->end = strlen(LINE); - } - end = name_end; - prev_end_char = *end; - *end = '\0'; - fail_if (xstrdup(*var, line)); - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -664,46 +645,49 @@ static int names_1(char** restrict var) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int chars(char** restrict var) +static int +chars(char **restrict var) { - if (too_few) - return 0; - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "too few parameters"); - line = end, too_few = 1; - } - else - { - char* arg_end = line; - char* call_end = arg_end; - int escape = 0, quote = 0; - while (*arg_end) - { - char c = *arg_end++; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); - } - else if (quote) quote = (c != '"'); - else if (IS_END(c)) { arg_end--; break; } - else quote = (c == '"'); + char *arg_end, *call_end, c; + int escape, quote; + if (too_few) + return 0; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "too few parameters"); + line = end, too_few = 1; + } else { + arg_end = line; + call_end = arg_end; + escape = quote = 0; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (IS_END(c)) { + arg_end--; + break; + } else { + quote = c == '"'; + } + } + prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; + fail_if (xstrdup(*var, line)); + line = end; } - prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; - fail_if (xstrdup(*var, line)); - line = end; - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -712,25 +696,25 @@ static int chars(char** restrict var) * * @return Zero on success, -1 on error */ -static int quotes(void) +static int +quotes(void) { - char* line_ = line; - line = STREND(line); - *end = prev_end_char; - SKIP_SPACES(line); - if (*line && (*line != '"')) - { - char* arg_end = line; - SKIP_SPACES(arg_end); - NEW_ERROR(1, ERROR, "parameter must be in quotes"); - error->end = (size_t)(arg_end - LINE); - } - *end = '\0'; - line = line_; - - return 0; - fail: - return -1; + char *line_ = line, *arg_end; + line = STREND(line); + *end = prev_end_char; + SKIP_SPACES(line); + if (*line && *line != '"') { + arg_end = line; + SKIP_SPACES(arg_end); + NEW_ERROR(1, ERROR, "parameter must be in quotes"); + error->end = (size_t)(arg_end - LINE); + } + *end = '\0'; + line = line_; + + return 0; +fail: + return -1; } @@ -739,23 +723,23 @@ static int quotes(void) * * @return Whether the currently line has unparsed parameters, -1 on error */ -static int have_more_parameters(void) +static int +have_more_parameters(void) { - if (too_few) - return 0; - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "too few parameters"); - line = end, too_few = 1; - return 0; - } - return 1; - fail: - return -1; + if (too_few) + return 0; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "too few parameters"); + line = end, too_few = 1; + return 0; + } + return 1; +fail: + return -1; } @@ -765,32 +749,33 @@ static int have_more_parameters(void) * @param keyword The keyword * @return Zero on success, -1 on error */ -static int test_for_keyword(const char* restrict keyword) +static int +test_for_keyword(const char *restrict keyword) { - int ok, r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - ok = (strstr(line, keyword) == line); - line += strlen(keyword); - ok = ok && ((*line == '\0') || (*line == ' ')); - if (ok) - { - end = line; - prev_end_char = *end, *end = '\0'; - return 0; - } - line -= strlen(keyword); - end = line; - SKIP_SPACES(end); - prev_end_char = *end, *end = '\0'; - NEW_ERROR(1, ERROR, "expecting keyword ‘%s’", keyword); - error->end = error->start + 1; - - return 0; - fail: - return -1; + int ok, r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + ok = (strstr(line, keyword) == line); + line += strlen(keyword); + ok = ok && (!*line || *line == ' '); + if (ok) { + end = line; + prev_end_char = *end; + *end = '\0'; + return 0; + } + line -= strlen(keyword); + end = line; + SKIP_SPACES(end); + prev_end_char = *end, *end = '\0'; + NEW_ERROR(1, ERROR, "expecting keyword ‘%s’", keyword); + error->end = error->start + 1; + + return 0; +fail: + return -1; } @@ -802,52 +787,53 @@ static int test_for_keyword(const char* restrict keyword) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int keys(mds_kbdc_tree_t** restrict var) +static int +keys(mds_kbdc_tree_t **restrict var) { - char* arg_end; - char* call_end; - int r, escape = 0, quote = 0, triangle; - r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - arg_end = line; - call_end = arg_end; - triangle = (*arg_end == '<'); - while (*arg_end) - { - char c = *arg_end++ ; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + char *arg_end, *call_end, c; + int r, escape = 0, quote = 0, triangle; + r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + arg_end = line; + call_end = arg_end; + triangle = *arg_end == '<'; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (c == '\"') { + quote = 1; + } else if (c == '>') { + triangle = 0; + } else if (IS_END(c) && !triangle) { + arg_end--; + break; + } } - else if (quote) quote = (c != '"'); - else if (c == '\"') quote = 1; - else if (c == '>') triangle = 0; - else if (IS_END(c) && !triangle) { arg_end--; break; } - } - prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; - if (*line == '<') - { - NEW_SUBNODE(keys, KEYS); - *var = (mds_kbdc_tree_t*)subnode; - fail_if (xstrdup(subnode->keys, line)); - } - else - { - NEW_SUBNODE(string, STRING); - *var = (mds_kbdc_tree_t*)subnode; - fail_if (xstrdup(subnode->string, line)); - } - line = end; - - return 0; - fail: - return -1; + prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; + if (*line == '<') { + NEW_SUBNODE(keys, KEYS); + *var = (mds_kbdc_tree_t *)subnode; + fail_if (xstrdup(subnode->keys, line)); + } else { + NEW_SUBNODE(string, STRING); + *var = (mds_kbdc_tree_t *)subnode; + fail_if (xstrdup(subnode->string, line)); + } + line = end; + + return 0; +fail: + return -1; } @@ -860,41 +846,45 @@ static int keys(mds_kbdc_tree_t** restrict var) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int pure_keys(char** restrict var) +static int +pure_keys(char **restrict var) { - char* arg_end; - char* call_end; - int r, escape = 0, quote = 0, triangle; - r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - arg_end = line; - call_end = arg_end; - triangle = (*arg_end == '<'); - while (*arg_end) - { - char c = *arg_end++ ; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + char *arg_end, *call_end, c; + int r, escape = 0, quote = 0, triangle; + r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + arg_end = line; + call_end = arg_end; + triangle = *arg_end == '<'; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (c == '\"') { + quote = 1; + } else if (c == '>') { + triangle = 0; + } else if (IS_END(c) && !triangle) { + arg_end--; + break; + } } - else if (quote) quote = (c != '"'); - else if (c == '\"') quote = 1; - else if (c == '>') triangle = 0; - else if (IS_END(c) && !triangle) { arg_end--; break; } - } - prev_end_char = *arg_end, *arg_end = '\0'; - fail_if (xstrdup(*var, line)); - end = arg_end, line = end; - - return 0; - fail: - return -1; + prev_end_char = *arg_end, *arg_end = '\0'; + fail_if (xstrdup(*var, line)); + end = arg_end, line = end; + + return 0; +fail: + return -1; } @@ -906,65 +896,54 @@ static int pure_keys(char** restrict var) * @param stack_orig The size of the stack when `SEQUENCE` was called * @return Zero on success, -1 on error */ -static int sequence(int mapseq, size_t stack_orig) +static int +sequence(int mapseq, size_t stack_orig) { - if (mapseq && (*line == '(')) - { - NEW_NODE(unordered, UNORDERED); - node->loc_end = node->loc_start + 1; - BRANCH(")"); - line++; - } - else if (*line == '[') - { - NEW_NODE(alternation, ALTERNATION); - node->loc_end = node->loc_start + 1; - BRANCH("]"); - line++; - } - else if (*line == '.') - { - NEW_NODE(nothing, NOTHING); - node->loc_end = node->loc_start + 1; - LEAF; - line++; - } - else if (strchr("])", *line)) - { - end = line + 1; - prev_end_char = *end, *end = '\0'; - if (stack_ptr == stack_orig) - NEW_ERROR(1, ERROR, "runaway ‘%s’", line); - else - { - stack_ptr--; - if (strcmp(line, keyword_stack[stack_ptr])) - NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); - NEXT; + if (mapseq && *line == '(') { + NEW_NODE(unordered, UNORDERED); + node->loc_end = node->loc_start + 1; + BRANCH(")"); + line++; + } else if (*line == '[') { + NEW_NODE(alternation, ALTERNATION); + node->loc_end = node->loc_start + 1; + BRANCH("]"); + line++; + } else if (*line == '.') { + NEW_NODE(nothing, NOTHING); + node->loc_end = node->loc_start + 1; + LEAF; + line++; + } else if (strchr("])", *line)) { + end = line + 1; + prev_end_char = *end, *end = '\0'; + if (stack_ptr == stack_orig) { + NEW_ERROR(1, ERROR, "runaway ‘%s’", line); + } else { + stack_ptr--; + if (strcmp(line, keyword_stack[stack_ptr])) + NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); + NEXT; + } + *end = prev_end_char; + line++; + } else if (*line == '<') { + NEW_NODE(keys, KEYS); + NO_JUMP; + PURE_KEYS(keys); + LEAF; + node->loc_end = (size_t)(line - LINE); + } else { + NEW_NODE(string, STRING); + NO_JUMP; + CHARS(string); + LEAF; + node->loc_end = (size_t)(line - LINE); } - *end = prev_end_char; - line++; - } - else if (*line == '<') - { - NEW_NODE(keys, KEYS); - NO_JUMP; - PURE_KEYS(keys); - LEAF; - node->loc_end = (size_t)(line - LINE); - } - else - { - NEW_NODE(string, STRING); - NO_JUMP; - CHARS(string); - LEAF; - node->loc_end = (size_t)(line - LINE); - } - - return 0; + + return 0; fail: - return -1; + return -1; } @@ -973,23 +952,23 @@ static int sequence(int mapseq, size_t stack_orig) * * @param stack_orig The size of the stack when `SEQUENCE` was called */ -static int sequence_fully_popped(size_t stack_orig) +static int +sequence_fully_popped(size_t stack_orig) { - if (stack_ptr == stack_orig) - return 0; - end = line + 1; - NEW_ERROR(1, ERROR, "premature end of sequence"); - while (stack_ptr > stack_orig) - { - stack_ptr--; - NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); - error->start = tree_stack[stack_ptr][0]->loc_start; - error->end = tree_stack[stack_ptr][0]->loc_end; - } - - return 0; - fail: - return -1; + if (stack_ptr == stack_orig) + return 0; + end = line + 1; + NEW_ERROR(1, ERROR, "premature end of sequence"); + while (stack_ptr > stack_orig) { + stack_ptr--; + NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); + error->start = tree_stack[stack_ptr][0]->loc_start; + error->end = tree_stack[stack_ptr][0]->loc_end; + } + + return 0; +fail: + return -1; } @@ -1002,62 +981,54 @@ static int sequence_fully_popped(size_t stack_orig) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_else(void) +static int +parse_else(void) { - size_t i; - if (stack_ptr == 0) - { - NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); - return 0; - } - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - end = STREND(line); - SKIP_SPACES(line); - i = stack_ptr - 1; - while (keyword_stack[i] == NULL) - i--; - if (strcmp(keyword_stack[i], "if")) - { - stack_ptr--; - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); - } - else if (*line == '\0') - { - /* else */ - mds_kbdc_tree_if_t* supernode = &(tree_stack[stack_ptr - 1][0]->if_); - if (supernode->otherwise) - { - line = strstr(LINE, "else"); - end = line + 4, prev_end_char = *end; - NEW_ERROR(1, ERROR, "multiple ‘else’ statements"); - mds_kbdc_tree_free(supernode->otherwise); - supernode->otherwise = NULL; + size_t i; + if (!stack_ptr) { + NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); + return 0; } - tree_stack[stack_ptr] = &(supernode->otherwise); - } - else if ((strstr(line, "if") == line) && ((line[2] == ' ') || (line[2] == '\0'))) - { - /* else if */ - mds_kbdc_tree_if_t* supernode = &(tree_stack[stack_ptr - 1][0]->if_); - NEW_NODE(if, IF); - node->loc_end = node->loc_start + 2; - end = line += 2, prev_end_char = *end, *end = '\0'; - CHARS(condition); - END; - tree_stack[stack_ptr] = &(supernode->otherwise); - BRANCH(NULL); - } - else - { - NEW_ERROR(1, ERROR, "expecting nothing or ‘if’"); - stack_ptr--; - } - - return 0; - fail: - return -1; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + end = STREND(line); + SKIP_SPACES(line); + i = stack_ptr - 1; + while (!keyword_stack[i]) + i--; + if (strcmp(keyword_stack[i], "if")) { + stack_ptr--; + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); + } else if (!*line) { + /* else */ + mds_kbdc_tree_if_t *supernode = &tree_stack[stack_ptr - 1][0]->if_; + if (supernode->otherwise) { + line = strstr(LINE, "else"); + end = line + 4, prev_end_char = *end; + NEW_ERROR(1, ERROR, "multiple ‘else’ statements"); + mds_kbdc_tree_free(supernode->otherwise); + supernode->otherwise = NULL; + } + tree_stack[stack_ptr] = &supernode->otherwise; + } else if (strstr(line, "if") == line && (line[2] == ' ' || !line[2])) { + /* else if */ + mds_kbdc_tree_if_t *supernode = &tree_stack[stack_ptr - 1][0]->if_; + NEW_NODE(if, IF); + node->loc_end = node->loc_start + 2; + end = line += 2, prev_end_char = *end, *end = '\0'; + CHARS(condition); + END; + tree_stack[stack_ptr] = &(supernode->otherwise); + BRANCH(NULL); + } else { + NEW_ERROR(1, ERROR, "expecting nothing or ‘if’"); + stack_ptr--; + } + + return 0; +fail: + return -1; } @@ -1066,20 +1037,21 @@ static int parse_else(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_for(void) +static int +parse_for(void) { - NEW_NODE(for, FOR); - CHARS(first); - TEST_FOR_KEYWORD("to"); - CHARS(last); - TEST_FOR_KEYWORD("as"); - CHARS(variable); - END; - BRANCH("for"); - - return 0; - fail: - return -1; + NEW_NODE(for, FOR); + CHARS(first); + TEST_FOR_KEYWORD("to"); + CHARS(last); + TEST_FOR_KEYWORD("as"); + CHARS(variable); + END; + BRANCH("for"); + + return 0; +fail: + return -1; } @@ -1088,52 +1060,48 @@ static int parse_for(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_let(void) +static int +parse_let(void) { - NEW_NODE(let, LET); - CHARS(variable); - TEST_FOR_KEYWORD(":"); - *end = prev_end_char; - SKIP_SPACES(line); - if (*line == '{') + NEW_NODE(let, LET); + CHARS(variable); + TEST_FOR_KEYWORD(":"); + *end = prev_end_char; + SKIP_SPACES(line); + if (*line == '{') #define inner value - BRANCH(NULL); + BRANCH(NULL); #undef inner - else - LEAF; - if (*line == '\0') - { - line = original, end = STREND(line), prev_end_char = '\0'; - NEW_ERROR(1, ERROR, "too few parameters"); - } - else if (*line != '{') - { + else + LEAF; + if (!*line) { + line = original, end = STREND(line), prev_end_char = '\0'; + NEW_ERROR(1, ERROR, "too few parameters"); + } else if (*line != '{') { #define node subnode - NEW_NODE(string, STRING); - NO_JUMP; - CHARS(string); - node->loc_end = (size_t)(end - LINE); + NEW_NODE(string, STRING); + NO_JUMP; + CHARS(string); + node->loc_end = (size_t)(end - LINE); #undef node - node->value = (mds_kbdc_tree_t*)subnode; - END; - } - else - { + node->value = (mds_kbdc_tree_t*)subnode; + END; + } else { #define node subnode #define inner elements - NEW_NODE(array, ARRAY); - BRANCH("}"); - node->loc_end = node->loc_start + 1; + NEW_NODE(array, ARRAY); + BRANCH("}"); + node->loc_end = node->loc_start + 1; #undef inner #undef node - in_array = 1; - line++; - return 1; - } - - return 0; - fail: - return -1; + in_array = 1; + line++; + return 1; + } + + return 0; +fail: + return -1; } @@ -1142,29 +1110,28 @@ static int parse_let(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_end(void) +static int +parse_end(void) { - if (stack_ptr == 0) - { - NEW_ERROR(1, ERROR, "runaway ‘end’ statement"); - return 0; - } - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - while (keyword_stack[--stack_ptr] == NULL); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "expecting a keyword after ‘end’"); - } - else if (strcmp(line, keyword_stack[stack_ptr])) - NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); - NEXT; - - return 0; - fail: - return -1; + if (!stack_ptr) { + NEW_ERROR(1, ERROR, "runaway ‘end’ statement"); + return 0; + } + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + while (!keyword_stack[--stack_ptr]); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "expecting a keyword after ‘end’"); + } else if (strcmp(line, keyword_stack[stack_ptr])) { + NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); + } + NEXT; + + return 0; +fail: + return -1; } @@ -1173,57 +1140,56 @@ static int parse_end(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_map(void) +static int +parse_map(void) { - size_t stack_orig = stack_ptr + 1; - char* colon; + size_t stack_orig = stack_ptr + 1; + char *colon; #define node supernode #define inner sequence - NEW_NODE(map, MAP); - node->loc_end = node->loc_start; - BRANCH(":"); + NEW_NODE(map, MAP); + node->loc_end = node->loc_start; + BRANCH(":"); #undef inner #undef node - SEQUENCE(1); - SEQUENCE_FULLY_POPPED; + SEQUENCE(1); + SEQUENCE_FULLY_POPPED; #define node supernode #define inner result - stack_ptr--; - *end = prev_end_char; - supernode->loc_end = (size_t)(end - LINE); - SKIP_SPACES(line); - if (colon = line, *line++ != ':') - { - LEAF; - prev_end_char = *end; - return 0; /* Not an error in functions, or if \set is access, even indirectly. */ - } - BRANCH(":"); + stack_ptr--; + *end = prev_end_char; + supernode->loc_end = (size_t)(end - LINE); + SKIP_SPACES(line); + if (colon = line, *line++ != ':') { + LEAF; + prev_end_char = *end; + return 0; /* Not an error in functions, or if \set is access, even indirectly. */ + } + BRANCH(":"); #undef inner #undef node - SEQUENCE(1); - SEQUENCE_FULLY_POPPED; - stack_ptr--; - *end = prev_end_char; - supernode->loc_end = (size_t)(end - LINE); - SKIP_SPACES(line); + SEQUENCE(1); + SEQUENCE_FULLY_POPPED; + stack_ptr--; + *end = prev_end_char; + supernode->loc_end = (size_t)(end - LINE); + SKIP_SPACES(line); #define node supernode - LEAF; + LEAF; #undef node - if (supernode->result == NULL) - { - NEW_ERROR(1, ERROR, "output missing"); - error->start = (size_t)(colon - LINE); - error->end = error->start + 1; - } - if (*line == '\0') - return prev_end_char = *end, 0; - end = STREND(line), prev_end_char = *end; - NEW_ERROR(1, ERROR, "too many parameters"); - - return 0; - fail: - return -1; + if (!supernode->result) { + NEW_ERROR(1, ERROR, "output missing"); + error->start = (size_t)(colon - LINE); + error->end = error->start + 1; + } + if (!*line) + return prev_end_char = *end, 0; + end = STREND(line), prev_end_char = *end; + NEW_ERROR(1, ERROR, "too many parameters"); + + return 0; +fail: + return -1; } @@ -1232,63 +1198,59 @@ static int parse_map(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_macro_call(void) +static int +parse_macro_call(void) { - char* old_end = end; - char old_prev_end_char = prev_end_char; - size_t stack_orig = stack_ptr + 1; - *end = prev_end_char; - end = strchrnul(line, '('); - prev_end_char = *end, *end = '\0'; - if (prev_end_char) - { + char *old_end = end; + char old_prev_end_char = prev_end_char; + size_t stack_orig = stack_ptr + 1; + *end = prev_end_char; + end = strchrnul(line, '('); + prev_end_char = *end, *end = '\0'; + if (prev_end_char) { #define node supernode #define inner arguments - NEW_NODE(macro_call, MACRO_CALL); - old_end = end, old_prev_end_char = prev_end_char; - NO_JUMP; - *old_end = '\0'; - CHARS(name); - BRANCH(NULL); - end = old_end, prev_end_char = old_prev_end_char; - line++; + NEW_NODE(macro_call, MACRO_CALL); + old_end = end, old_prev_end_char = prev_end_char; + NO_JUMP; + *old_end = '\0'; + CHARS(name); + BRANCH(NULL); + end = old_end, prev_end_char = old_prev_end_char; + line++; #undef inner #undef node - SEQUENCE(0); - SEQUENCE_FULLY_POPPED; + SEQUENCE(0); + SEQUENCE_FULLY_POPPED; #define node supernode - if (*line == ')') - { - line++; - SKIP_SPACES(line); - if (*line) - { - NEW_ERROR(1, ERROR, "extra token after macro call"); - error->end = strlen(LINE); - } - } - else - { - NEW_ERROR(1, ERROR, "missing ‘)’"); - error->start = (size_t)(strchr(LINE, '(') - LINE); - error->end = error->start + 1; - } - stack_ptr--; - NEXT; - return 0; + if (*line == ')') { + line++; + SKIP_SPACES(line); + if (*line) { + NEW_ERROR(1, ERROR, "extra token after macro call"); + error->end = strlen(LINE); + } + } else { + NEW_ERROR(1, ERROR, "missing ‘)’"); + error->start = (size_t)(strchr(LINE, '(') - LINE); + error->end = error->start + 1; + } + stack_ptr--; + NEXT; + return 0; #undef node - } - *old_end = '\0'; - end = old_end; - prev_end_char = old_prev_end_char; - if (strchr("}", *line)) - NEW_ERROR(1, ERROR, "runaway ‘%c’", *line); - else - NEW_ERROR(1, ERROR, "invalid syntax ‘%s’", line); - - return 0; - fail: - return -1; + } + *old_end = '\0'; + end = old_end; + prev_end_char = old_prev_end_char; + if (strchr("}", *line)) + NEW_ERROR(1, ERROR, "runaway ‘%c’", *line); + else + NEW_ERROR(1, ERROR, "invalid syntax ‘%s’", line); + + return 0; +fail: + return -1; } @@ -1297,48 +1259,44 @@ static int parse_macro_call(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_array_elements(void) +static int +parse_array_elements(void) { - for (;;) - { - SKIP_SPACES(line); - if (*line == '\0') - return 0; - else if (*line == '}') - { - line++; - end = STREND(line); - END; - line = end, prev_end_char = '\0'; - goto done; + for (;;) { + SKIP_SPACES(line); + if (!*line) { + return 0; + } else if (*line == '}') { + line++; + end = STREND(line); + END; + line = end, prev_end_char = '\0'; + goto done; + } else { + NEW_NODE(string, STRING); + if (strchr("[]()<>{}", *line)) { + mds_kbdc_tree_free((mds_kbdc_tree_t*)node); + NEW_ERROR(1, ERROR, "x-stray ‘%c’", *line); + error->end = error->start + 1; + goto done; + } + NO_JUMP; + CHARS(string); + LEAF; + node->loc_end = (size_t)(end - LINE); + *end = prev_end_char; + line = end; + } } - else - { - NEW_NODE(string, STRING); - if (strchr("[]()<>{}", *line)) - { - mds_kbdc_tree_free((mds_kbdc_tree_t*)node); - NEW_ERROR(1, ERROR, "x-stray ‘%c’", *line); - error->end = error->start + 1; - goto done; - } - NO_JUMP; - CHARS(string); - LEAF; - node->loc_end = (size_t)(end - LINE); - *end = prev_end_char; - line = end; - } - } - - fail: - return -1; - - done: - in_array = 0; - stack_ptr -= 2; - NEXT; - return 0; + +fail: + return -1; + +done: + in_array = 0; + stack_ptr -= 2; + NEXT; + return 0; } @@ -1347,50 +1305,47 @@ static int parse_array_elements(void) * * @return Zero on success, -1 on error */ -static int parse_line(void) +static int +parse_line(void) { -#define p(function) \ - do \ - { \ - fail_if (r = function(), r < 0); \ - if (r > 0) \ - goto redo; \ - } \ - while (0) - - int r; - - redo: - if (in_array) p (parse_array_elements); - else if (!strcmp(line, "have_chars")) - MAKE_LEAF(assumption_have_chars, ASSUMPTION_HAVE_CHARS, QUOTES_1(chars)); - else if (!strcmp(line, "have_range")) - MAKE_LEAF(assumption_have_range, ASSUMPTION_HAVE_RANGE, CHARS(first); CHARS(last); END); - else if (!strcmp(line, "have")) MAKE_LEAF(assumption_have, ASSUMPTION_HAVE, KEYS(data); END); - else if (!strcmp(line, "information")) MAKE_BRANCH(information, INFORMATION, NO_PARAMETERS("information")); - else if (!strcmp(line, "assumption")) MAKE_BRANCH(assumption, ASSUMPTION, NO_PARAMETERS("assumption")); - else if (!strcmp(line, "return")) MAKE_LEAF(return, RETURN, NO_PARAMETERS("return")); - else if (!strcmp(line, "continue")) MAKE_LEAF(continue, CONTINUE, NO_PARAMETERS("continue")); - else if (!strcmp(line, "break")) MAKE_LEAF(break, BREAK, NO_PARAMETERS("break")); - else if (!strcmp(line, "language")) MAKE_LEAF(information_language, INFORMATION_LANGUAGE, QUOTES_1(data)); - else if (!strcmp(line, "country")) MAKE_LEAF(information_country, INFORMATION_COUNTRY, QUOTES_1(data)); - else if (!strcmp(line, "variant")) MAKE_LEAF(information_variant, INFORMATION_VARIANT, QUOTES_1(data)); - else if (!strcmp(line, "include")) MAKE_LEAF(include, INCLUDE, QUOTES_1(filename)); - else if (!strcmp(line, "function")) MAKE_BRANCH(function, FUNCTION, NAMES_1(name)); - else if (!strcmp(line, "macro")) MAKE_BRANCH(macro, MACRO, NAMES_1(name)); - else if (!strcmp(line, "if")) MAKE_BRANCH(if, IF, CHARS(condition); END); - else if (!strcmp(line, "else")) p (parse_else); - else if (!strcmp(line, "for")) p (parse_for); - else if (!strcmp(line, "let")) p (parse_let); - else if (!strcmp(line, "end")) p (parse_end); - else if (strchr("\\\"<([0123456789", *line)) p (parse_map); - else p (parse_macro_call); - - *end = prev_end_char; - - return 0; - fail: - return -1; +#define p(function)\ + do {\ + fail_if ((r = function()) < 0);\ + if (r > 0)\ + goto redo;\ + } while (0) + + int r; + +redo: + if (in_array) p (parse_array_elements); + else if (!strcmp(line, "have_chars")) MAKE_LEAF(assumption_have_chars, ASSUMPTION_HAVE_CHARS, QUOTES_1(chars)); + else if (!strcmp(line, "have_range")) MAKE_LEAF(assumption_have_range, ASSUMPTION_HAVE_RANGE, CHARS(first); CHARS(last); END); + else if (!strcmp(line, "have")) MAKE_LEAF(assumption_have, ASSUMPTION_HAVE, KEYS(data); END); + else if (!strcmp(line, "information")) MAKE_BRANCH(information, INFORMATION, NO_PARAMETERS("information")); + else if (!strcmp(line, "assumption")) MAKE_BRANCH(assumption, ASSUMPTION, NO_PARAMETERS("assumption")); + else if (!strcmp(line, "return")) MAKE_LEAF(return, RETURN, NO_PARAMETERS("return")); + else if (!strcmp(line, "continue")) MAKE_LEAF(continue, CONTINUE, NO_PARAMETERS("continue")); + else if (!strcmp(line, "break")) MAKE_LEAF(break, BREAK, NO_PARAMETERS("break")); + else if (!strcmp(line, "language")) MAKE_LEAF(information_language, INFORMATION_LANGUAGE, QUOTES_1(data)); + else if (!strcmp(line, "country")) MAKE_LEAF(information_country, INFORMATION_COUNTRY, QUOTES_1(data)); + else if (!strcmp(line, "variant")) MAKE_LEAF(information_variant, INFORMATION_VARIANT, QUOTES_1(data)); + else if (!strcmp(line, "include")) MAKE_LEAF(include, INCLUDE, QUOTES_1(filename)); + else if (!strcmp(line, "function")) MAKE_BRANCH(function, FUNCTION, NAMES_1(name)); + else if (!strcmp(line, "macro")) MAKE_BRANCH(macro, MACRO, NAMES_1(name)); + else if (!strcmp(line, "if")) MAKE_BRANCH(if, IF, CHARS(condition); END); + else if (!strcmp(line, "else")) p (parse_else); + else if (!strcmp(line, "for")) p (parse_for); + else if (!strcmp(line, "let")) p (parse_let); + else if (!strcmp(line, "end")) p (parse_end); + else if (strchr("\\\"<([0123456789", *line)) p (parse_map); + else p (parse_macro_call); + + *end = prev_end_char; + + return 0; +fail: + return -1; #undef p } @@ -1406,63 +1361,62 @@ static int parse_line(void) * @param result_ Output parameter for the parsing result * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict result_) +int +parse_to_tree(const char *restrict filename, mds_kbdc_parsed_t *restrict result_) { - size_t line_n; - int r, saved_errno; - - - /* Prepare parsing. */ - result = result_; - stack_ptr = 0; - keyword_stack = NULL; - tree_stack = NULL; - in_array = 0; - - fail_if (xmalloc(result->source_code, 1, mds_kbdc_source_code_t)); - mds_kbdc_source_code_initialise(result->source_code); - - r = get_pathname(filename); - fail_if (r < 0); - if (r == 0) - return 0; - - fail_if (read_source_code()); - fail_if (allocate_stacks()); - - - /* Create a node-slot for the tree root. */ - *tree_stack = &(result->tree); - - /* Parse the file. */ - for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) - { - line = LINE; - SKIP_SPACES(line); - if (end = strchrnul(line, ' '), end == line) - continue; - prev_end_char = *end, *end = '\0'; - original = line; - too_few = 0; - - parse_line(); - } - - - /* Check parsing state. */ - fail_if (check_for_premature_end_of_file()); - fail_if (check_whether_file_is_empty()); - - /* Clean up. */ - free(keyword_stack); - free(tree_stack); - return 0; - - fail: - saved_errno = errno; - free(keyword_stack); - free(tree_stack); - return errno = saved_errno, -1; + size_t line_n; + int r, saved_errno; + + + /* Prepare parsing. */ + result = result_; + stack_ptr = 0; + keyword_stack = NULL; + tree_stack = NULL; + in_array = 0; + + fail_if (xmalloc(result->source_code, 1, mds_kbdc_source_code_t)); + mds_kbdc_source_code_initialise(result->source_code); + + fail_if ((r = get_pathname(filename)) < 0); + if (!r) + return 0; + + fail_if (read_source_code()); + fail_if (allocate_stacks()); + + + /* Create a node-slot for the tree root. */ + *tree_stack = &(result->tree); + + /* Parse the file. */ + for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) { + line = LINE; + SKIP_SPACES(line); + if ((end = strchrnul(line, ' ')) == line) + continue; + prev_end_char = *end, *end = '\0'; + original = line; + too_few = 0; + + parse_line(); + } + + + /* Check parsing state. */ + fail_if (check_for_premature_end_of_file()); + fail_if (check_whether_file_is_empty()); + + /* Clean up. */ + free(keyword_stack); + free(tree_stack); + return 0; + +fail: + saved_errno = errno; + free(keyword_stack); + free(tree_stack); + return errno = saved_errno, -1; } @@ -1493,4 +1447,3 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict res #undef in_range #undef PRINT_STACK #undef DEBUG_PROC - |