Example #1
0
// 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);
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
// 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);
    }
}
Example #7
0
/**
 * 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;
}
Example #8
0
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)]);
    }
}
Example #9
0
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;
	}
}
Example #10
0
// 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`");
    }
}
Example #11
0
/**
 * 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;
}
Example #12
0
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);
}
Example #13
0
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);
}
Example #14
0
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);
}
Example #15
0
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;
}
Example #16
0
File: acc.c Project: pbui/adder
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;
}
Example #17
0
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;
}
Example #18
0
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;
}
Example #19
0
// 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);
}
Example #20
0
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;
}
Example #21
0
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;
}
Example #22
0
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;
}
Example #23
0
// 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);
}
Example #24
0
// 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);
}
Example #25
0
/**
 * 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;
}
Example #26
0
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);
    }
}
Example #27
0
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;
}
Example #28
0
/**
@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;
}
Example #29
0
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;
    }
    }
}
Example #30
0
static inline void skip_seps(struct compiler *compiler)
{
    while (is_sep(compiler))
        lexer_next(compiler);
}