// Parses a multi-import statement. void parse_multi_import(Parser *parser) { Lexer *lexer = parser->lexer; // Ensure there's at least one string within the // parentheses EXPECT(TOKEN_STRING, "Expected package name after `(`"); // Expect a comma separated list of strings while (lexer->token == TOKEN_STRING) { // Import the package char *name = lexer_extract_string(lexer->value.identifier); import(parser, name); // Consume the string lexer_next(lexer); // Expect a comma EXPECT(TOKEN_COMMA, "Expected `,` after package name"); lexer_next(lexer); } // Expect a close parenthesis EXPECT(TOKEN_CLOSE_PARENTHESIS, "Expected `)` to close import list"); lexer_next(lexer); }
struct node *parse_equality(struct compiler *compiler) { struct node *result = parse_boolean_unary(compiler); while(is_equality_op(compiler)) { struct node *node; if(lexer_current(compiler) == T_NO_EQUALITY) node = alloc_node(compiler, N_NO_EQUALITY); else { node = alloc_node(compiler, N_BINARY_OP); node->op = lexer_current(compiler); } node->left = result; lexer_next(compiler); node->right = parse_boolean_unary(compiler); result = node; } return result; }
bool parse(ast_t* package, source_t* source, rule_t start, const char* expected) { assert(package != NULL); assert(source != NULL); assert(expected != NULL); // Open the lexer lexer_t* lexer = lexer_open(source); if(lexer == NULL) return false; // Create a parser and attach the lexer parser_t* parser = POOL_ALLOC(parser_t); parser->source = source; parser->lexer = lexer; parser->token = lexer_next(lexer); parser->last_matched = NULL; parser->last_token_line = 0; parser->next_flags = 0; parser->failed = false; // Parse given start rule builder_fn_t build_fn; ast_t* ast = start(parser, &build_fn, expected); if(ast == PARSE_ERROR) ast = NULL; if(ast == RULE_NOT_FOUND) { syntax_error(parser, expected, NULL, NULL); ast = NULL; } if(parser->failed) { ast_free(ast); ast = NULL; } lexer_close(lexer); token_free(parser->token); POOL_FREE(parser_t, parser); if(ast == NULL) { source_close(source); return false; } assert(ast_id(ast) == TK_MODULE); assert(ast_data(ast) == NULL); ast_setdata(ast, source); ast_add(package, ast); return true; }
token_t* lexer_nextif(lexer_state_t* lex, token_types_t tokentype) { if ( lex->error ) return NULL; if ( lexer_matches(lex, tokentype) ) { return lexer_next(lex); } return NULL; }
token_t* lexer_nextif_special(lexer_state_t* lex, const char* token) { if ( lex->error ) return NULL; if ( lexer_matches(lex, special_token) ) { if ( strcmp((char*) lexer_cur(lex)->value, token) == 0 ) { return lexer_next(lex); } } return NULL; }
// Parses a list of import statements at the top of a file. void parse_imports(Parser *parser) { Lexer *lexer = parser->lexer; // Continually parse import statements while (lexer->token == TOKEN_IMPORT) { // Consume the `import` lexer_next(lexer); // Parse the rest of the import parse_import(parser); } }
/** * Parses "depends" statements from the head of the script file. These scripts * will be build before this one is and will be compiled into the same bytecode * buffer. * compiler: an instance of compiler. * lexer: an instance of lexer. * returns: true if all dependencies parsed correctly, and false if an error * occurs. */ static bool parse_dependencies(Compiler * compiler, Lexer * lexer) { char * token; LexerType type; size_t len; /* get current token */ token = lexer_current_token(lexer, &type, &len); /* while there are more depends statements, build those scripts */ while(tokens_equal(token, len, LANG_DEPENDS, LANG_DEPENDS_LEN)) { char * scriptFileName; /* check next token is a string */ token = lexer_next(lexer, &type, &len); if(type != LEXERTYPE_STRING) { compiler->err = COMPILERERR_MALFORMED_DEPENDS; return false; } scriptFileName = calloc(len + 1, sizeof(char)); strncpy(scriptFileName, token, len); /* build dependency script */ if(!compiler_build_file(compiler, scriptFileName)) { free(scriptFileName); return false; } free(scriptFileName); /* check for terminating semicolon */ token = lexer_next(lexer, &type, &len); if(!tokens_equal(token, len, LANG_ENDSTATEMENT, LANG_ENDSTATEMENT_LEN)) { compiler->err = COMPILERERR_EXPECTED_ENDSTATEMENT; return false; } token = lexer_next(lexer, &type, &len); } return true; }
void parse_sep(struct compiler *compiler) { switch (lexer_current(compiler)) { case T_LINE: case T_SEP: lexer_next(compiler); break; default: COMPILER_ERROR(compiler, "Expected seperator but found %s", token_type_names[lexer_current(compiler)]); } }
db_int processCreate(db_lexer_t *lexerp, db_int end, db_query_mm_t *mmp) { lexer_next(lexerp); switch (lexerp->token.info) { case DB_LEXER_TOKENINFO_LITERAL_TABLE: #if defined(DB_CTCONF_SETTING_FEATURE_CREATE_TABLE) && 1==DB_CTCONF_SETTING_FEATURE_CREATE_TABLE return createTable(lexerp, end, mmp); #else return -1; #endif default: return -1; } }
// Parses a single import statement. void parse_import(Parser *parser) { Lexer *lexer = parser->lexer; // Parse a multi-import statement if the next token is // an open parenthesis if (lexer->token == TOKEN_OPEN_PARENTHESIS) { // Consume the open parenthesis lexer_next(lexer); // Multi-import statement parse_multi_import(parser); } else if (lexer->token == TOKEN_STRING) { // Single import statement char *name = lexer_extract_string(lexer->value.identifier); import(parser, name); // Consume the string token lexer_next(lexer); } else { // Unexpected token UNEXPECTED("Expected package name or `(` after `import`"); } }
/** * Builds a script buffer and adds its code to the bytecode output buffer and * stores references to its functions and variables in the Compiler object. * After several input buffers of scripts have been built, you can copy the * bytecode to a buffer for execution using compiler_bytecode(). * compiler: an instance of compiler that will receive the bytecode. * input: an input buffer that contains the script code. * inputLen: the number of bytes in length of the input. * returns: true if the compile operation succeeds, and false if it fails. */ bool compiler_build(Compiler * compiler, char * input, size_t inputLen) { assert(compiler != NULL); assert(input != NULL); assert(inputLen > 0); Lexer * lexer = lexer_new(input, inputLen); LexerType type; size_t tokenLen; /* check that lexer alloc didn't fail, and push symtbl for global variables */ if(lexer == NULL || !symtblstk_push(compiler)) { compiler_set_err(compiler, COMPILERERR_ALLOC_FAILED); lexer_free(lexer); return false; } compiler_set_err(compiler, COMPILERERR_SUCCESS); /* get first token */ lexer_next(lexer, &type, &tokenLen); /* handle script imports/"depends" */ if(!parse_dependencies(compiler, lexer)) { return false; } /* compile loop */ while(lexer_current_token(lexer, &type, &tokenLen) != NULL) { parse_function_definitions(compiler, lexer); /* handle errors */ if(lexer_get_err(lexer) != LEXERERR_SUCCESS) { compiler->err = COMPILERERR_LEXER_ERR; compiler->lexerErr = lexer_get_err(lexer); compiler->errorLineNum = lexer_line_num(lexer); } if(compiler->err != COMPILERERR_SUCCESS) { compiler->lexerErr = lexer_get_err(lexer); compiler->errorLineNum = lexer_line_num(lexer); lexer_free(lexer); return false; } } /* we're done here: pop globals symtable */ symtbl_free(symtblstk_pop(compiler)); lexer_free(lexer); return true; }
struct node *parse_low_boolean_unary(struct compiler *compiler) { if(lexer_current(compiler) == T_NOT) { struct node *result = alloc_node(compiler, N_NOT); lexer_next(compiler); result->left = parse_expression(compiler); return result; } else return parse_expression(compiler); }
struct node *parse_boolean_unary(struct compiler *compiler) { if(lexer_current(compiler) == T_NOT_SIGN) { struct node *result = alloc_node(compiler, N_NOT); lexer_next(compiler); result->left = parse_arithmetic(compiler); return result; } else return parse_arithmetic(compiler); }
struct node *parse_unary(struct compiler *compiler) { if(lexer_current(compiler) == T_ADD || lexer_current(compiler) == T_SUB) { struct node *result = alloc_node(compiler, N_UNARY_OP); result->op = lexer_current(compiler) + OP_TO_UNARY; lexer_next(compiler); result->left = parse_lookup_chain(compiler);; return result; } else return parse_lookup_chain(compiler); }
struct node *parse_array_element(struct compiler *compiler) { struct node *result = alloc_node(compiler, N_ARRAY_ELEMENT); result->left = parse_expression(compiler); if(lexer_current(compiler) == T_COMMA) { lexer_next(compiler); result->right = parse_array_element(compiler); } else result->right = 0; return result; }
int main(int argc, char *argv[]) { struct Lexer l; lexer_state s; if (argc != 2) { fprintf(stderr, "Usage: %s path\n", argv[0]); return EXIT_FAILURE; } s = lexer_init(&l, argv[1]); do { s = lexer_next(&l); } while (s == LEXER_READY); return EXIT_SUCCESS; }
struct node *parse_low_boolean(struct compiler *compiler) { struct node *result = parse_low_boolean_unary(compiler); while(lexer_current(compiler) == T_AND || lexer_current(compiler) == T_OR) { struct node *node = alloc_node(compiler, N_BOOLEAN); node->op = lexer_current(compiler); node->left = result; lexer_next(compiler); node->right = parse_low_boolean_unary(compiler); result = node; } return result; }
struct node *parse_term(struct compiler *compiler) { struct node *result = parse_unary(compiler); while(lexer_current(compiler) == T_MUL || lexer_current(compiler) == T_DIV) { struct node *node = alloc_node(compiler, N_BINARY_OP); node->op = lexer_current(compiler); node->left = result; lexer_next(compiler); node->right = parse_unary(compiler); result = node; } return result; }
// Parses a package into bytecode. Sets the main function // index property on the package. void parse_package(VirtualMachine *vm, Package *package) { // Create the lexer used for all parent and child parsers Lexer lexer = lexer_new(package->source); lexer_next(&lexer); // Create a new parser Parser parser; parser.parent = NULL; parser.lexer = &lexer; parser.fn = fn_new(vm, package, &package->main_fn); parser.scope_depth = 0; parser.locals_count = 0; // Parse the import statements at the top of the file parse_imports(&parser); // Parse the rest of the file parse_block(&parser, TOKEN_EOF); }
struct node *parse_arithmetic(struct compiler *compiler) { struct node *result = parse_term(compiler); while (lexer_current(compiler) == T_ADD || lexer_current(compiler) == T_SUB) { struct node *node = alloc_node(compiler, N_BINARY_OP); node->op = lexer_current(compiler); node->left = result; lexer_next(compiler); node->right = parse_term(compiler); result = node; } return result; }
struct node *parse_boolean_and(struct compiler *compiler) { struct node *result = parse_equality(compiler); while(lexer_current(compiler) == T_AND_BOOLEAN) { struct node *node = alloc_node(compiler, N_BOOLEAN); node->op = lexer_current(compiler); node->left = result; lexer_next(compiler); node->right = parse_equality(compiler); result = node; } return result; }
static void fetch_next_lexer_token(parser_t* parser, bool free_prev_token) { token_t* old_token = parser->token; token_t* new_token = lexer_next(parser->lexer); if(old_token != NULL) parser->last_token_line = token_line_number(old_token); if(old_token != NULL && token_get_id(new_token) == TK_EOF) { // Use location of last token for EOF to get better error reporting token_set_pos(new_token, token_source(old_token), token_line_number(old_token), token_line_position(old_token)); } if(free_prev_token) token_free(old_token); parser->token = new_token; }
// Get the next token ready for when we need it static void get_next_token(build_parser_t* builder) { assert(builder != NULL); if(builder->have_token) return; if(builder->token != NULL) token_free(builder->token); builder->token = lexer_next(builder->lexer); assert(builder->token != NULL); ast_token_id id; switch(token_get_id(builder->token)) { case TK_LPAREN_NEW: case TK_LPAREN: id = AT_LPAREN; break; case TK_RPAREN: id = AT_RPAREN; break; case TK_LSQUARE_NEW: case TK_LSQUARE: id = AT_LSQUARE; break; case TK_RSQUARE: id = AT_RSQUARE; break; case TK_LBRACE: id = AT_LBRACE; break; case TK_RBRACE: id = AT_RBRACE; break; case TK_EOF: id = AT_EOF; break; case TK_LEX_ERROR: id = AT_ERROR; break; case TK_ID: id = AT_ID; break; case TK_STRING: id = AT_STRING; break; default: id = AT_TOKEN; break; } //printf("Got token %s %d -> %d\n", token_print(builder->token), // token_get_id(builder->token), id); builder->id = id; builder->have_token = true; builder->line = token_line_number(builder->token); builder->pos = token_line_position(builder->token); }
// Parses an assignment to a new variable (using a `let` // token). void parse_initial_assignment(Parser *parser) { Lexer *lexer = parser->lexer; // Consume the `let` token lexer_next(lexer); }
/** * A subparser function for compiler_build() that looks at the current token, * checks for a 'function' token. If found, it proceeds to evaluate the function * declaration, make note of the number of arguments, and store the index where * the function will begin in the byte code. This function then dispatches * subparsers that define stack variables, evaluate logical blocks (if, else, * while, etc), and evaluate straight code. * c: an instance of Compiler. * l: an instance of lexer. * returns: false if the current token is not the start of a function declaration * ('function'), and true if it is. If an error occurs, function returns true, * but c->err is set to a relevant error code. */ static bool parse_function_definitions(Compiler * c, Lexer * l) { /* * A Function definition looks like so: * * function [EXPORTED] [NAME] ( [ARG1], [ARG2], ... ) { * [code] * } * * The code below parses these tokens and then dispatches the straight code * parsers to handle the function body. */ bool exported = false; size_t len; LexerType type; char * token = lexer_current_token(l, &type, &len); char * name; size_t nameLen; int numArgs; int numVars; /* check that this is a function declaration token */ if(!tokens_equal(token, len, LANG_FUNCTION, LANG_FUNCTION_LEN)) { c->err = COMPILERERR_UNEXPECTED_TOKEN; return false; } /* advance to next token. if is is EXPORTED, take note for later */ token = lexer_next(l, &type, &len); if(tokens_equal(token, len, LANG_EXPORTED, LANG_EXPORTED_LEN)) { exported = true; token = lexer_next(l, &type, &len); } /* this is the name token, store it and check for correct type */ name = token; nameLen = len; if(type != LEXERTYPE_KEYVAR || is_keyword(name, nameLen)) { c->err = COMPILERERR_EXPECTED_FNAME; return true; } /* check if name is too long */ if(nameLen > GS_MAX_FUNCTION_NAME_LEN) { c->err = COMPILERERR_FUNCTION_NAME_TOO_LONG; return true; } /* check for the open parenthesis */ token = lexer_next(l, &type, &len); if(!tokens_equal(token, len, LANG_OPARENTH, LANG_OPARENTH_LEN)) { c->err = COMPILERERR_EXPECTED_OPARENTH; return true; } /* we're going down a level. push new symbol table to stack */ if(!symtblstk_push(c)) { c->err = COMPILERERR_ALLOC_FAILED; return true; } /* parse the arguments, return if the process fails */ if((numArgs = parse_arguments(c, l)) == -1) { return true; } /* check for open brace defining start of function "{" */ token = lexer_next(l, &type, &len); if(!tokens_equal(token, len, LANG_OBRACKET, LANG_OBRACKET_LEN)) { c->err = COMPILERERR_EXPECTED_OBRACKET; return true; } token = lexer_next(l, &type, &len); /****************************** Do function body ****************************/ /* handle variable declarations */ if((numVars = define_variables(c, l)) == -1) { return false; } /* retrieve next token (it was modified by define_variable */ token = lexer_current_token(l, &type, &len); /* store the function name, location in the output, and # of args and vars */ if(!function_store_definition(c, name, nameLen, numArgs, numVars, exported)) { return true; } if(!parse_body(c, l)) { return true; } /* retrieve current token (it was modified by parse_body) */ token = lexer_current_token(l, &type, &len); /****************************** End function body ***************************/ /* check for closing brace defining end of body "}" */ if(!tokens_equal(token, len, LANG_CBRACKET, LANG_CBRACKET_LEN)) { c->err = COMPILERERR_EXPECTED_CBRACKET; return true; } /* push default return value. if no other return is given, this value is * returned */ buffer_append_char(vm_buffer(c->vm), OP_NULL_PUSH); /* pop function frame and return to calling function */ buffer_append_char(vm_buffer(c->vm), OP_FRM_POP); token = lexer_next(l, &type, &len); /* we're done here! pop the symbol table for this function off the stack. */ ht_free(symtblstk_pop(c)); return true; }
struct node *parse_identifier(struct compiler *compiler) { rt_value symbol = rt_symbol_from_lexer(compiler); lexer_next(compiler); switch (lexer_current(compiler)) { case T_ASSIGN_ADD: case T_ASSIGN_SUB: case T_ASSIGN_MUL: case T_ASSIGN_DIV: { struct node *result; enum token_type op_type = lexer_current(compiler) - OP_TO_ASSIGN; lexer_next(compiler); if (rt_symbol_is_const(symbol)) result = alloc_node(compiler, N_ASSIGN_CONST); else result = alloc_node(compiler, N_ASSIGN); result->right = alloc_node(compiler, N_BINARY_OP); result->right->op = op_type; if (rt_symbol_is_const(symbol)) { result->left = &self_node; result->middle = (void *)symbol; result->right->left = alloc_node(compiler, N_CONST); result->right->left->left = &self_node; result->right->left->right = (void *)symbol; } else { result->left = (void *)scope_get(compiler->current_block, symbol); result->right->left = alloc_node(compiler, N_VAR); result->right->left->left = (void *)scope_get(compiler->current_block, symbol); } result->right->right = parse_expression(compiler); return result; } case T_ASSIGN: { struct node *result; lexer_next(compiler); if (rt_symbol_is_const(symbol)) { result = alloc_node(compiler, N_ASSIGN_CONST); result->left = &self_node; result->middle = (void *)symbol; } else { result = alloc_node(compiler, N_ASSIGN); result->left = (void *)scope_get(compiler->current_block, symbol); } result->right = parse_expression(compiler); return result; } // Function call or local variable default: return parse_call(compiler, symbol, &self_node, true); } }
array_t * parse (lexer_t *lex) { unsigned i; array_t stack; array_init(&stack, sizeof(parser_stack_t)); parser_stack_t initial; bzero(&initial, sizeof(initial)); array_add(&stack, &initial); array_t *result = 0; while (stack.size > 0) { parser_stack_t *current = array_get(&stack, stack.size-1); const parser_state_t *state = parser_states + current->state; for (i = 0; i < state->num_actions; ++i) if (state->actions[i].token == lex->token) break; if (i >= state->num_actions) { char *msg = strdup("syntax error, expected"); for (i = 0; i < state->num_actions; ++i) { char *glue; if (i == 0) glue = " "; else if (i == state->num_actions-1) glue = ", or "; else glue = ", "; char *nmsg; asprintf(&nmsg, "%s%s\"%s\"", msg, glue, token_names[state->actions[i].token]); free(msg); msg = nmsg; } derror(&lex->loc, "%s\n", msg); free(msg); } const parser_action_t *action = &state->actions[i]; if (action->state_or_length < 0) { if (action->rule == 0) { result = current->token.ptr; break; } unsigned num_tokens = -action->state_or_length; parser_stack_t *target = array_get(&stack, stack.size-num_tokens); parser_stack_t *base = array_get(&stack, stack.size-num_tokens-1); const parser_state_t *base_state = parser_states + base->state; token_t reduced = target->token; reduced.id = action->rule; reduced.last = current->token.last; if (action->reducer) { token_t tokens[num_tokens]; for (i = 0; i < num_tokens; ++i) tokens[i] = (target+i)->token; action->reducer(&reduced, tokens, action->reducer_tag); } target->token = reduced; for (i = 0; i < base_state->num_gotos; ++i) { if (base_state->gotos[i].rule == action->rule) { target->state = base_state->gotos[i].state; break; } } array_resize(&stack, stack.size-num_tokens+1); } else { parser_stack_t *new_stack = array_add(&stack, 0); bzero(new_stack, sizeof(*new_stack)); new_stack->state = action->state_or_length; new_stack->token.id = lex->token; new_stack->token.first = lex->base; new_stack->token.last = lex->ptr; new_stack->token.loc = lex->loc; lexer_next(lex); } } array_dispose(&stack); return result; }
/** @brief Create a table. @details This function creates a table from a simplified CREATE TABLE statement. This function assumes that the 'CREATE' and 'TABLE' tokens have been thrown away; that is, the next token to process is the table's name. @param lexerp A pointer to the lexer instance variable that is generating the token stream. @param end The index of the first character in the command being lexed that is not part of the CREATE statement. @param mmp A pointer to the per-query memory manager being used to process this query. @returns @c 1 if the table was created successfully, @c -1 if an error occurred, @c 0 otherwise. */ db_int createTable(db_lexer_t *lexerp, db_int end, db_query_mm_t *mmp) { db_fileref_t newtable; char *tablename; /* Create a file with table name. */ if (1==lexer_next(lexerp) && (db_uint8)DB_LEXER_TT_IDENT == lexerp->token.type) { tablename = db_qmm_falloc(mmp, gettokenlength(&(lexerp->token))+1); gettokenstring(&(lexerp->token), tablename, lexerp); if (db_fileexists(tablename)) { DB_ERROR_MESSAGE("duplicate table name", lexerp->token.start, lexerp->command); db_qmm_ffree(mmp, tablename); return -1; } newtable = db_openwritefile(tablename); } /* Throw away the bracket. */ if (1!=lexer_next(lexerp) || DB_LEXER_TT_LPAREN != lexerp->token.type) { DB_ERROR_MESSAGE("missing '('", lexerp->offset, lexerp->command); db_fileclose(newtable); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } db_uint8 attrcount = 0; int i; db_lexer_token_t *arr = db_qmm_balloc(mmp, 0); while (1==lexer_next(lexerp) && DB_LEXER_TT_RPAREN != lexerp->token.type) { if (attrcount > 0 && DB_LEXER_TT_COMMA != lexerp->token.type) { DB_ERROR_MESSAGE("duplicate attr name", lexerp->token.start, lexerp->command); db_qmm_bfree(mmp, arr); db_fileclose(newtable); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } else if (attrcount > 0 && 1!=lexer_next(lexerp)) { DB_ERROR_MESSAGE("dangling comma", lexerp->offset, lexerp->command); db_qmm_bfree(mmp, arr); db_fileclose(newtable); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } if (DB_LEXER_TT_IDENT == lexerp->token.type) { int length = gettokenlength(&(lexerp->token)); char attrname[length+1]; gettokenstring(&(lexerp->token), attrname, lexerp); /* Validate unique attribute name. */ for (i = 0; i < (int)attrcount; ++i) { if (1==token_stringequal(arr+i, attrname, length, lexerp, 0)) { DB_ERROR_MESSAGE("duplicate attr name", lexerp->token.start, lexerp->command); db_qmm_bfree(mmp, arr); db_fileclose(newtable); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } } /* Add current token to set to check in future. */ arr=db_qmm_bextend(mmp, sizeof(db_lexer_token_t)); arr[0] = lexerp->token; /* We will perform some hackiness here. Since we need to know the number of attributes before we write, we will simply store the values of the types, and if necessary, lengths, in the tokens. */ if (1==lexer_next(lexerp) && DB_LEXER_TOKENINFO_TYPE_DBINT == lexerp->token.info) { arr[0].type = DB_INT; arr[0].bcode = sizeof(db_int); } /* Extract size of the string. */ else if (DB_LEXER_TOKENINFO_TYPE_DBSTRING == lexerp->token.info && 1==lexer_next(lexerp) && DB_LEXER_TT_LPAREN == lexerp->token.type && 1==lexer_next(lexerp) && DB_LEXER_TT_INT == lexerp->token.type && (length=getintegerfromtoken(&(lexerp->token), lexerp)) > 0 && length <= DB_CTCONF_SETTING_MAXSTRINGLENGTH && 1==lexer_next(lexerp) && DB_LEXER_TT_RPAREN == lexerp->token.type) { arr[0].type = DB_STRING; arr[0].bcode = length; } /* TODO: Implement future types here. */ else { DB_ERROR_MESSAGE("bad attribute type", lexerp->token.start, lexerp->command); db_qmm_bfree(mmp, arr); db_fileclose(newtable); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } } else { DB_ERROR_MESSAGE("bad attribute declaration", lexerp->token.start, lexerp->command); db_qmm_bfree(mmp, arr); db_fileclose(newtable); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } attrcount++; } /* Build out the new relation file. */ db_filewrite(newtable, &attrcount, sizeof(db_uint8)); db_uint8 offset = 0; db_uint8 temp; while (attrcount > 0) { /* Write out the length of the attribute name. */ db_uint8 length = (db_uint8)gettokenlength(&(arr[((int)attrcount)-1]))+1; char attrname[(int)length]; gettokenstring(&(arr[((int)attrcount)-1]), attrname, lexerp); /* Write out the attribute name. */ db_filewrite(newtable, &length, sizeof(db_uint8)); db_filewrite(newtable, attrname, (size_t)length); /* Write out the attribute type. */ temp = (db_uint8)(arr[((int)attrcount)-1].type); db_filewrite(newtable, &temp, sizeof(db_uint8)); /* Write out the offset and size. */ temp = (db_uint8)arr[((int)attrcount)-1].bcode; db_filewrite(newtable, &offset, sizeof(db_uint8)); db_filewrite(newtable, &temp, sizeof(db_uint8)); offset += temp; attrcount--; } db_qmm_bfree(mmp, arr); db_fileclose(newtable); /* Throw away the bracket. */ if (DB_LEXER_TT_RPAREN != lexerp->token.type) { DB_ERROR_MESSAGE("missing ')'", lexerp->offset, lexerp->command); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } if (end < lexerp->offset) { DB_ERROR_MESSAGE("malformed statement", 0, lexerp->command); db_fileremove(tablename); db_qmm_ffree(mmp, tablename); return -1; } db_qmm_ffree(mmp, tablename); return 1; }
struct node *parse_factor(struct compiler *compiler) { switch (lexer_current(compiler)) { case T_BEGIN: return parse_begin(compiler); case T_IF: return parse_if(compiler); case T_UNLESS: return parse_unless(compiler); case T_CASE: return parse_case(compiler); case T_CLASS: return parse_class(compiler); case T_MODULE: return parse_module(compiler); case T_DEF: return parse_method(compiler); case T_YIELD: return parse_yield(compiler); case T_RETURN: return parse_return(compiler); case T_BREAK: return parse_break(compiler); case T_NEXT: return parse_next(compiler); case T_REDO: return parse_redo(compiler); case T_SQUARE_OPEN: { struct node *result = alloc_node(compiler, N_ARRAY); lexer_next(compiler); if(lexer_current(compiler) == T_SQUARE_CLOSE) result->left = 0; else result->left = parse_array_element(compiler); lexer_match(compiler, T_SQUARE_CLOSE); return result; } case T_STRING: { struct node *result = alloc_node(compiler, N_STRING); result->left = (void *)lexer_token(compiler)->start; lexer_next(compiler); return result; } case T_STRING_START: { struct node *result = alloc_node(compiler, N_STRING_CONTINUE); result->left = 0; result->middle = (void *)lexer_token(compiler)->start; lexer_next(compiler); result->right = parse_statements(compiler); while(lexer_current(compiler) == T_STRING_CONTINUE) { struct node *node = alloc_node(compiler, N_STRING_CONTINUE); node->left = result; node->middle = (void *)lexer_token(compiler)->start; lexer_next(compiler); node->right = parse_statements(compiler); result = node; } if(lexer_require(compiler, T_STRING_END)) { struct node *node = alloc_node(compiler, N_STRING_START); node->left = result; node->right = (void *)lexer_token(compiler)->start; lexer_next(compiler); return node; } return result; } case T_SELF: { lexer_next(compiler); return &self_node; } case T_TRUE: { lexer_next(compiler); return alloc_node(compiler, N_TRUE); } case T_FALSE: { lexer_next(compiler); return alloc_node(compiler, N_FALSE); } case T_NIL: { lexer_next(compiler); return &nil_node; } case T_NUMBER: { struct node *result = alloc_node(compiler, N_NUMBER); char *text = get_token_str(lexer_token(compiler)); result->left = (void* )atoi(text); lexer_next(compiler); return result; } case T_IVAR: { rt_value symbol = rt_symbol_from_lexer(compiler); lexer_next(compiler); switch (lexer_current(compiler)) { case T_ASSIGN_ADD: case T_ASSIGN_SUB: case T_ASSIGN_MUL: case T_ASSIGN_DIV: { struct node *result; enum token_type op_type = lexer_current(compiler) - OP_TO_ASSIGN; lexer_next(compiler); result = alloc_node(compiler, N_IVAR_ASSIGN); result->right = alloc_node(compiler, N_BINARY_OP); result->right->op = op_type; result->right->left = alloc_node(compiler, N_IVAR); result->right->left->left = (void *)symbol; result->right->right = parse_expression(compiler); result->left = (void *)symbol; return result; } case T_ASSIGN: { struct node *result; lexer_next(compiler); result = alloc_node(compiler, N_IVAR_ASSIGN); result->left = (void *)symbol; result->right = parse_expression(compiler); return result; } default: { struct node *result = alloc_node(compiler, N_IVAR); result->left = (void *)symbol; return result; } } } case T_IDENT: return parse_identifier(compiler); case T_EXT_IDENT: return parse_call(compiler, 0, &self_node, false); case T_PARAM_OPEN: { lexer_next(compiler); struct node *result = parse_statements(compiler); lexer_match(compiler, T_PARAM_CLOSE); return result; } default: { COMPILER_ERROR(compiler, "Expected expression but found %s", token_type_names[lexer_current(compiler)]); lexer_next(compiler); return 0; } } }
static inline void skip_seps(struct compiler *compiler) { while (is_sep(compiler)) lexer_next(compiler); }