LIBUPCOREAPI int parser_rewind(parser* par) noexcept { if (!par) { return sexp_badarg; } else if (!par->loaded) { return sexp_badstate; } allocator* const alloc = par->alloc; assert(alloc); slist_clear<parser_token_block, &parser_token_block::node>(&par->open_stack, alloc); slist_clear<parser_token_block, &parser_token_block::node>(&par->unread_stack, alloc); verify(sexp_success == lexer_rewind(&par->lex)); par->prev_column = 0; par->prev_line = 0; par->error_count = 0; par->warning_count = 0; return sexp_success; }
// Parses a set of constant arguments struct list *parse_constant_args(struct lexer_state *lexer, enum token_type close) { struct value *arg = NULL; struct list *args = list_new(); // First check for empty list lex(lexer); if(lexer->error == UNRECOGNIZED_TOKEN) { print_error(lexer, LEX_ERROR); clear_value_list(args); return NULL; } if(lexer->error == END_OF_INPUT) { print_error(lexer, UNEXPECTED_END); clear_value_list(args); return NULL; } // If we already have close token, just return empty list if(lexer->type == close) return args; else lexer_rewind(lexer); while(lexer->error == OK) { // First parse a value and add it to the list arg = parse_constant(lexer); if(!arg) { clear_function_list(args); return NULL; } list_push_back(args, arg); // Now checking for a separator or end of the list lex(lexer); if(lexer->error == UNRECOGNIZED_TOKEN) { print_error(lexer, LEX_ERROR); clear_value_list(args); return NULL; } if(lexer->error == END_OF_INPUT) { print_error(lexer, UNEXPECTED_END); clear_value_list(args); return NULL; } if(lexer->type == close) break; // If the list is still open, we expect a separator if(lexer->type != SEPARATOR) { print_error(lexer, INVALID_ELEMENT); clear_value_list(args); return NULL; } } return args; }
// Parses a function definition struct function *parse_function(struct lexer_state *lexer) { int error = 0; int i = 0; struct function *function = NULL; // First getting the identifier lex(lexer); if(lexer->error == UNRECOGNIZED_TOKEN) { print_error(lexer, LEX_ERROR); return NULL; } if(lexer->error == END_OF_INPUT) { print_error(lexer, UNEXPECTED_END); return NULL; } if(lexer->type != IDENT) { print_error(lexer, EXPECTED_IDENT); return NULL; } // Storing the identifier function = function_new(); function->name = strdup(lexer->value.sval); // Figuring out what type of function this is function->type = USER; // Until proven otherwise // Checking against primitive and form lists for(i = 0; *(PRIMITIVE_FUNCTION_NAMES[i]); i++) { if(!strcmp(PRIMITIVE_FUNCTION_NAMES[i], function->name)) { function->type = PRIMITIVE; function->index = i; } } for(i = 0; *(FUNCTIONAL_FORM_NAMES[i]); i++) { if(!strcmp(FUNCTIONAL_FORM_NAMES[i], function->name)) { function->type = FORM; function->index = i; } } // Now checking for possible arguments if(function->type == PRIMITIVE) { lex(lexer); if(lexer->error == UNRECOGNIZED_TOKEN) { print_error(lexer, LEX_ERROR); function_delete(function); return NULL; } // Now checking for opening paren if(lexer->error == OK && lexer->type == OPEN_SPEC) { function->args = parse_constant_args(lexer, CLOSE_SPEC); if(!function->args) { function_delete(function); return NULL; } } else { lexer_rewind(lexer); } } else if(function->type == FORM) { // A functional form requires arguments if(!require_token(lexer, OPEN_FORM)) { print_error(lexer, EXPECTED_ARGS); function_delete(function); return NULL; } function->args = parse_function_args(lexer); if(!function->args) { function_delete(function); return NULL; } } return function; }