From 462f67c6aa49afc8db59d711bd3c793ca14960eb Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 14 Dec 2024 20:26:04 +0000 Subject: [PATCH] asm: implement import and instruction parsing --- asm/assembler/class.c | 17 +- asm/include/ivy/asm/assembler.h | 2 +- asm/include/ivy/asm/bin.h | 3 + asm/include/ivy/asm/lex.h | 1 + asm/lex.c | 3 + asm/parse/block.c | 381 ++++++++++++++++++++++++++++++++ asm/parse/constpool.c | 6 +- asm/parse/import.c | 160 ++++++++++++++ asm/parse/parse.c | 14 +- asm/parse/parse.h | 4 +- asm/parse/unit.c | 231 ++++++++++++++++++- 11 files changed, 805 insertions(+), 17 deletions(-) diff --git a/asm/assembler/class.c b/asm/assembler/class.c index 1dae63d..c1d8015 100644 --- a/asm/assembler/class.c +++ b/asm/assembler/class.c @@ -6,7 +6,7 @@ static enum ivy_status init_scope(struct ivy_assembler *as, struct assembler_sco { struct ivy_bin_class header = {0}; - header.c_ident = b_i32_htob(attrib[IVY_ASM_ATTRIB_IDENT]); + header.c_ident = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_IDENT]); assembler_write_data(as, &header, sizeof header); @@ -23,14 +23,19 @@ static enum ivy_status put_xval( switch (type) { case IVY_ASM_XVAL_PROPERTY: entry.e_type = b_i32_htob(IVY_CLASS_TABLE_PROP); - entry.e_property.p_ident = b_i32_htob(attrib[IVY_ASM_ATTRIB_IDENT]); - entry.e_property.p_get = b_i32_htob(attrib[IVY_ASM_ATTRIB_GET]); - entry.e_property.p_set = b_i32_htob(attrib[IVY_ASM_ATTRIB_SET]); + entry.e_property.p_ident + = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_IDENT]); + entry.e_property.p_get + = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_GET]); + entry.e_property.p_set + = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_SET]); break; case IVY_ASM_XVAL_MEMBER_VAR: entry.e_type = b_i32_htob(IVY_CLASS_TABLE_MVAR); - entry.e_mvar.m_ident = b_i32_htob(attrib[IVY_ASM_ATTRIB_IDENT]); - entry.e_mvar.m_index = b_i32_htob(attrib[IVY_ASM_ATTRIB_INDEX]); + entry.e_mvar.m_ident + = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_IDENT]); + entry.e_mvar.m_index + = b_i32_htob((uint32_t)attrib[IVY_ASM_ATTRIB_INDEX]); break; default: return IVY_ERR_NOT_SUPPORTED; diff --git a/asm/include/ivy/asm/assembler.h b/asm/include/ivy/asm/assembler.h index 6b606b9..613e548 100644 --- a/asm/include/ivy/asm/assembler.h +++ b/asm/include/ivy/asm/assembler.h @@ -54,7 +54,7 @@ enum ivy_assembler_scope_type { IVY_ASM_SCOPE_IMPORT, }; -typedef unsigned int ivy_assembler_attrib_table[__IVY_ASM_ATTRIB_COUNT]; +typedef unsigned long long ivy_assembler_attrib_table[__IVY_ASM_ATTRIB_COUNT]; IVY_API enum ivy_static ivy_assembler_create(FILE *out, struct ivy_assembler **as); IVY_API enum ivy_status ivy_assembler_finish(struct ivy_assembler *as); diff --git a/asm/include/ivy/asm/bin.h b/asm/include/ivy/asm/bin.h index 50f126d..2f05efa 100644 --- a/asm/include/ivy/asm/bin.h +++ b/asm/include/ivy/asm/bin.h @@ -112,5 +112,8 @@ struct ivy_bin_constpool { struct ivy_bin_constpool_table_entry c_table[]; }; +struct ivy_bin_import_table_entry { + b_i32 e_ident; +}; #endif diff --git a/asm/include/ivy/asm/lex.h b/asm/include/ivy/asm/lex.h index 94f83fb..fc180d6 100644 --- a/asm/include/ivy/asm/lex.h +++ b/asm/include/ivy/asm/lex.h @@ -30,6 +30,7 @@ enum ivy_asm_keyword { IVY_ASM_KW_IMPORT, IVY_ASM_KW_BLOCK, IVY_ASM_KW_CONSTPOOL, + IVY_ASM_KW_PACKAGE, IVY_ASM_KW_CLASS, IVY_ASM_KW_END, __IVY_ASM_KW_INDEX_LIMIT, diff --git a/asm/lex.c b/asm/lex.c index 41ac251..a0eac79 100644 --- a/asm/lex.c +++ b/asm/lex.c @@ -28,6 +28,7 @@ static struct lex_token_def keywords[] = { LEX_TOKEN_DEF(IVY_ASM_KW_CONSTPOOL, "@constpool"), LEX_TOKEN_DEF(IVY_ASM_KW_CLASS, "@class"), LEX_TOKEN_DEF(IVY_ASM_KW_BLOCK, "@block"), + LEX_TOKEN_DEF(IVY_ASM_KW_PACKAGE, "@package"), LEX_TOKEN_DEF(IVY_ASM_KW_END, "@end"), }; static const size_t nr_keywords = sizeof keywords / sizeof keywords[0]; @@ -766,6 +767,7 @@ static enum ivy_status read_number(struct ivy_asm_lexer *lex) char s[] = {c, 0}; b_string_append_cstr(str, s); + token_len++; advance(lex); } @@ -1030,6 +1032,7 @@ const char *ivy_asm_keyword_to_string(enum ivy_asm_keyword keyword) ENUM_STR(IVY_ASM_KW_CLASS); ENUM_STR(IVY_ASM_KW_BLOCK); ENUM_STR(IVY_ASM_KW_IMPORT); + ENUM_STR(IVY_ASM_KW_PACKAGE); ENUM_STR(IVY_ASM_KW_END); default: return ""; diff --git a/asm/parse/block.c b/asm/parse/block.c index e69de29..f8bd383 100644 --- a/asm/parse/block.c +++ b/asm/parse/block.c @@ -0,0 +1,381 @@ +#include "parse.h" + +#include +#include +#include +#include +#include +#include +#include + +#define HASH_SELF 0x2d19e518d40792b7 +#define HASH_POOL 0x8c22f10da88b1083 +#define HASH_SP 0x08d93e07b5793c56 +#define HASH_BP 0x08a64407b54decef + +#define REG_INDEX_INVALID ((unsigned long long)-1) + +enum instr_component { + INSTR_NONE = 0, + INSTR_OPCODE, + INSTR_OPERAND, + INSTR_OPERAND_SEPARATOR, + INSTR_OPERAND_INDEX_LEFT, + INSTR_OPERAND_INDEX_BASE, + INSTR_OPERAND_INDEX_SEPARATOR, + INSTR_OPERAND_INDEX_OFFSET, + INSTR_OPERAND_INDEX_RIGHT, +}; + +enum index_base { + INDEX_NONE = 0, + INDEX_SELF, + INDEX_POOL, + INDEX_SP, + INDEX_BP, +}; + +enum arg_type { + ARG_NONE = 0, + ARG_CONST, + ARG_REG, + ARG_INDEX_REG, + ARG_INDEX_CONST, +}; + +struct arg { + enum arg_type arg_type; + b_queue_entry arg_entry; + + union { + struct ivy_asm_token *arg_const; + struct { + struct ivy_asm_token *reg_token; + unsigned long long reg_index; + } arg_reg; + struct { + enum index_base index_base; + struct ivy_asm_token *index_base_token; + + struct ivy_asm_token *index_offset; + unsigned long long index_offset_reg; + } arg_index_reg; + + struct { + enum index_base index_base; + struct ivy_asm_token *index_base_token; + + struct ivy_asm_token *index_offset; + } arg_index_const; + }; +}; + +struct block_parser_state { + struct parser_state s_base; + unsigned int s_prev_token; + enum instr_component s_prev_component; + + struct ivy_asm_token *s_mnemonic; + + b_queue s_args; + struct arg *s_current_arg; +}; + +static unsigned long long get_register_index(struct ivy_asm_token *tok) +{ + if (tok->t_type != IVY_ASM_TOK_IDENT) { + return REG_INDEX_INVALID; + } + + const char *s = tok->t_str; + if (tolower(s[0]) != 'x') { + return REG_INDEX_INVALID; + } + + char index_str[5] = {0}; + strncpy(index_str + 1, s, sizeof index_str - 1); + char *ep = NULL; + unsigned long long index = strtoul(index_str, &ep, 10); + + if (*ep || index >= 256) { + return REG_INDEX_INVALID; + } + + return index; +} + +static enum index_base get_index_base(struct ivy_asm_token *tok) +{ + if (tok->t_type != IVY_ASM_TOK_IDENT) { + return REG_INDEX_INVALID; + } + + const char *s = tok->t_str; + uint64_t hash = b_hash_string(s); + + switch (hash) { + case HASH_SELF: + if (!strcmp(s, "self")) { + return INDEX_SELF; + } + + return INDEX_NONE; + case HASH_POOL: + if (!strcmp(s, "pool")) { + return INDEX_POOL; + } + + return INDEX_NONE; + case HASH_SP: + if (!strcmp(s, "sp")) { + return INDEX_SP; + } + + return INDEX_NONE; + case HASH_BP: + if (!strcmp(s, "bp")) { + return INDEX_BP; + } + + return INDEX_NONE; + default: + return INDEX_NONE; + } +} + +static enum ivy_status write_instruction(struct block_parser_state *state) +{ + return IVY_OK; +} + +static enum ivy_status push_const_arg(struct block_parser_state *state, struct ivy_asm_token *tok) +{ + struct arg *arg = malloc(sizeof *arg); + if (!arg) { + return IVY_ERR_NO_MEMORY; + } + + memset(arg, 0x0, sizeof *arg); + + arg->arg_type = ARG_CONST; + arg->arg_const = tok; + + b_queue_push_back(&state->s_args, &arg->arg_entry); + return IVY_OK; +} + +static enum ivy_status push_reg_arg( + struct block_parser_state *state, struct ivy_asm_token *tok, unsigned long long reg_index) +{ + struct arg *arg = malloc(sizeof *arg); + if (!arg) { + return IVY_ERR_NO_MEMORY; + } + + memset(arg, 0x0, sizeof *arg); + + arg->arg_type = ARG_REG; + arg->arg_reg.reg_token = tok; + arg->arg_reg.reg_index = reg_index; + + b_queue_push_back(&state->s_args, &arg->arg_entry); + return IVY_OK; +} + +static enum ivy_status parse_linefeed( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + switch (state->s_prev_component) { + case INSTR_NONE: + return IVY_OK; + case INSTR_OPCODE: + case INSTR_OPERAND: + case INSTR_OPERAND_INDEX_RIGHT: + state->s_prev_component = INSTR_NONE; + return write_instruction(state); + default: + return IVY_ERR_BAD_SYNTAX; + } +} + +static enum ivy_status parse_int( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + switch (state->s_prev_component) { + case INSTR_OPCODE: + case INSTR_OPERAND_SEPARATOR: + push_const_arg(state, tok); + state->s_prev_component = INSTR_OPERAND; + return IVY_OK; + case INSTR_OPERAND_INDEX_SEPARATOR: + state->s_current_arg->arg_type = ARG_INDEX_CONST; + state->s_current_arg->arg_index_const.index_offset = tok; + state->s_prev_component = INSTR_OPERAND_INDEX_OFFSET; + return IVY_OK; + default: + return IVY_ERR_BAD_SYNTAX; + } +} + +static enum ivy_status parse_ident( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + unsigned long long x = 0; + + switch (state->s_prev_component) { + case INSTR_NONE: + state->s_mnemonic = tok; + state->s_prev_component = INSTR_OPCODE; + return IVY_OK; + case INSTR_OPCODE: + case INSTR_OPERAND_SEPARATOR: + x = get_register_index(tok); + if (x == REG_INDEX_INVALID) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_component = INSTR_OPERAND; + return push_reg_arg(state, tok, x); + case INSTR_OPERAND_INDEX_LEFT: + x = get_index_base(tok); + if (x == INDEX_NONE) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_current_arg->arg_type = ARG_INDEX_REG; + state->s_current_arg->arg_index_reg.index_base_token = tok; + state->s_current_arg->arg_index_reg.index_base = x; + state->s_prev_component = INSTR_OPERAND_INDEX_BASE; + return IVY_OK; + default: + return IVY_ERR_BAD_SYNTAX; + + } + + /* not sure what this is but we aren't expecting it. */ + return IVY_ERR_BAD_SYNTAX; +} + +static enum ivy_status parse_label( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + /* not sure what this is but we aren't expecting it. */ + return IVY_ERR_BAD_SYNTAX; +} + +static enum ivy_status parse_comma( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + switch (state->s_prev_component) { + case INSTR_OPERAND: + case INSTR_OPERAND_INDEX_RIGHT: + state->s_prev_component = INSTR_OPERAND_SEPARATOR; + return IVY_OK; + case INSTR_OPERAND_INDEX_BASE: + state->s_prev_component = INSTR_OPERAND_INDEX_SEPARATOR; + return IVY_OK; + default: + return IVY_ERR_BAD_SYNTAX; + } +} + +static enum ivy_status parse_left_bracket( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + switch (state->s_prev_component) { + case INSTR_OPCODE: + case INSTR_OPERAND_SEPARATOR: + break; + default: + return IVY_ERR_BAD_SYNTAX; + } + + struct arg *arg = malloc(sizeof *arg); + if (!arg) { + return IVY_ERR_NO_MEMORY; + } + + memset(arg, 0x0, sizeof *arg); + + state->s_current_arg = arg; + state->s_prev_component = INSTR_OPERAND_INDEX_LEFT; + return IVY_OK; +} + +static enum ivy_status parse_right_bracket( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_component != INSTR_OPERAND_INDEX_OFFSET) { + return IVY_ERR_BAD_SYNTAX; + } + + b_queue_push_back(&state->s_args, &state->s_current_arg->arg_entry); + state->s_current_arg = NULL; + state->s_prev_component = INSTR_OPERAND; + + return IVY_OK; +} + +static enum ivy_status parse_end( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct block_parser_state *state + = (struct block_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_component != INSTR_NONE) { + return IVY_ERR_BAD_SYNTAX; + } + + asm_parser_pop_state(ctx, NULL); + + return IVY_OK; +} + +static void init_state(struct ivy_asm_parser *ctx, struct parser_state *state) +{ +} + +static void finish_state(struct ivy_asm_parser *ctx, struct parser_state *state) +{ +} + +struct parser_state_type block_parser_state_type = { + .n_init_state = init_state, + .n_finish_state = finish_state, + .n_state_size = sizeof(struct block_parser_state), + .n_token_parsers = { + TOK_PARSER(IDENT, parse_ident), + TOK_PARSER(LABEL, parse_label), + TOK_PARSER(INT, parse_int), + TOK_PARSER(LINEFEED, parse_linefeed), + }, + .n_symbol_parsers = { + SYM_PARSER(LEFT_BRACKET, parse_left_bracket), + SYM_PARSER(RIGHT_BRACKET, parse_right_bracket), + SYM_PARSER(COMMA, parse_comma), + }, + .n_keyword_parsers = { + KW_PARSER(END, parse_end), + }, +}; \ No newline at end of file diff --git a/asm/parse/constpool.c b/asm/parse/constpool.c index d618388..c76c51f 100644 --- a/asm/parse/constpool.c +++ b/asm/parse/constpool.c @@ -229,13 +229,13 @@ static enum ivy_status parse_left_paren( switch (state->s_prev_token) { case IVY_ASM_KW_SELECTOR: - asm_parser_push_state(ctx, ASM_PARSER_SELECTOR); + asm_parser_push_state(ctx, ASM_PARSER_SELECTOR, NULL); break; case IVY_ASM_KW_IDENT: - asm_parser_push_state(ctx, ASM_PARSER_IDENT); + asm_parser_push_state(ctx, ASM_PARSER_IDENT, NULL); break; case IVY_ASM_KW_ATOM: - asm_parser_push_state(ctx, ASM_PARSER_ATOM); + asm_parser_push_state(ctx, ASM_PARSER_ATOM, NULL); break; default: return IVY_ERR_BAD_SYNTAX; diff --git a/asm/parse/import.c b/asm/parse/import.c index e69de29..5ccc3b7 100644 --- a/asm/parse/import.c +++ b/asm/parse/import.c @@ -0,0 +1,160 @@ +#include "parse.h" + +#include +#include +#include +#include + +struct import_parser_state { + struct parser_state s_base; + unsigned int s_prev_token; + + unsigned long long s_package_ident; + bool s_package_ident_set; +}; + +static enum ivy_status parse_package( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct import_parser_state *state + = (struct import_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_KW_IMPORT && state->s_prev_token != IVY_ASM_TOK_LINEFEED) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_package_ident_set = false; + state->s_prev_token = IVY_ASM_KW_PACKAGE; + return IVY_OK; +} + +static enum ivy_status parse_label( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct import_parser_state *state + = (struct import_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_LEFT_BRACKET) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_package_ident_set) { + return IVY_ERR_BAD_SYNTAX; + } + + if (strcmp(tok->t_str, "ident") != 0) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_LABEL; + return IVY_OK; +} + +static enum ivy_status parse_int( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct import_parser_state *state + = (struct import_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_LABEL) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_package_ident_set) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_INT; + state->s_package_ident = tok->t_int.uv; + state->s_package_ident_set = true; + return IVY_OK; +} + +static enum ivy_status parse_left_bracket( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct import_parser_state *state + = (struct import_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_KW_PACKAGE) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_package_ident_set) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_SYM_LEFT_BRACKET; + return IVY_OK; +} + +static enum ivy_status parse_right_bracket( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct import_parser_state *state + = (struct import_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_INT) { + return IVY_ERR_BAD_SYNTAX; + } + + if (!state->s_package_ident_set) { + return IVY_ERR_BAD_SYNTAX; + } + + ivy_assembler_attrib_table attrib = { + [IVY_ASM_ATTRIB_IDENT] = state->s_package_ident, + }; + + ivy_assembler_put_xval(ctx->p_assembler, IVY_ASM_XVAL_PACKAGE_REF, attrib); + + state->s_prev_token = IVY_ASM_SYM_RIGHT_BRACKET; + state->s_package_ident_set = false; + + return IVY_OK; +} + +static enum ivy_status parse_end( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct import_parser_state *state + = (struct import_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_KW_IMPORT && state->s_prev_token != IVY_ASM_SYM_RIGHT_BRACKET) { + return IVY_ERR_BAD_SYNTAX; + } + + asm_parser_pop_state(ctx, NULL); + return IVY_OK; +} + +static void init_state(struct ivy_asm_parser *ctx, struct parser_state *p) +{ + ivy_assembler_begin_scope(ctx->p_assembler, IVY_ASM_SCOPE_IMPORT, NULL); + + struct import_parser_state *state = (struct import_parser_state *)p; + state->s_prev_token = IVY_ASM_KW_IMPORT; +} + +static void finish_state(struct ivy_asm_parser *ctx, struct parser_state *state) +{ + ivy_assembler_end_scope(ctx->p_assembler); +} + +struct parser_state_type import_parser_state_type = { + .n_init_state = init_state, + .n_finish_state = finish_state, + .n_state_size = sizeof(struct import_parser_state), + .n_token_parsers = { + TOK_PARSER(LABEL, parse_label), + TOK_PARSER(INT, parse_int), + }, + .n_keyword_parsers = { + KW_PARSER(PACKAGE, parse_package), + KW_PARSER(END, parse_end), + }, + .n_symbol_parsers = { + SYM_PARSER(LEFT_BRACKET, parse_left_bracket), + SYM_PARSER(RIGHT_BRACKET, parse_right_bracket), + }, +}; \ No newline at end of file diff --git a/asm/parse/parse.c b/asm/parse/parse.c index d425e73..13e654f 100644 --- a/asm/parse/parse.c +++ b/asm/parse/parse.c @@ -9,6 +9,8 @@ extern struct parser_state_type constpool_parser_state_type; extern struct parser_state_type ident_parser_state_type; extern struct parser_state_type selector_parser_state_type; extern struct parser_state_type atom_parser_state_type; +extern struct parser_state_type import_parser_state_type; +extern struct parser_state_type block_parser_state_type; static const struct parser_state_type *parser_state_types[] = { [ASM_PARSER_UNIT] = &unit_parser_state_type, @@ -16,6 +18,8 @@ static const struct parser_state_type *parser_state_types[] = { [ASM_PARSER_IDENT] = &ident_parser_state_type, [ASM_PARSER_SELECTOR] = &selector_parser_state_type, [ASM_PARSER_ATOM] = &atom_parser_state_type, + [ASM_PARSER_IMPORT] = &import_parser_state_type, + [ASM_PARSER_BLOCK] = &block_parser_state_type, }; static const size_t nr_parser_state_types = sizeof parser_state_types / sizeof parser_state_types[0]; @@ -29,7 +33,7 @@ enum ivy_status ivy_asm_parser_create(struct ivy_asm_parser **out) memset(parser, 0x0, sizeof *parser); - asm_parser_push_state(parser, ASM_PARSER_UNIT); + asm_parser_push_state(parser, ASM_PARSER_UNIT, NULL); *out = parser; return IVY_OK; @@ -112,7 +116,9 @@ static const struct parser_state_type *get_parser_state_type(enum parser_state_t return parser_state_types[type]; } -struct parser_state *asm_parser_push_state(struct ivy_asm_parser *parser, enum parser_state_type_id type) +struct parser_state *asm_parser_push_state( + struct ivy_asm_parser *parser, enum parser_state_type_id type, + const ivy_assembler_attrib_table attrib) { const struct parser_state_type *type_info = get_parser_state_type(type); @@ -130,6 +136,10 @@ struct parser_state *asm_parser_push_state(struct ivy_asm_parser *parser, enum p state->s_type = type_info; + if (attrib) { + memcpy(state->s_attrib, attrib, sizeof attrib); + } + if (type_info->n_init_state) { type_info->n_init_state(parser, state); } diff --git a/asm/parse/parse.h b/asm/parse/parse.h index 7ae7cc0..cdb68b1 100644 --- a/asm/parse/parse.h +++ b/asm/parse/parse.h @@ -1,6 +1,7 @@ #ifndef _PARSE_PARSE_H_ #define _PARSE_PARSE_H_ +#include #include #include @@ -53,6 +54,7 @@ struct parser_state_type { struct parser_state { b_queue_entry s_entry; const struct parser_state_type *s_type; + ivy_assembler_attrib_table s_attrib; void *s_previous_value; }; @@ -61,7 +63,7 @@ struct ivy_asm_parser { b_queue p_state; }; -extern struct parser_state *asm_parser_push_state(struct ivy_asm_parser *parser, enum parser_state_type_id type); +extern struct parser_state* asm_parser_push_state(struct ivy_asm_parser* parser, enum parser_state_type_id type, const ivy_assembler_attrib_table attrib); extern void asm_parser_pop_state(struct ivy_asm_parser *parser, void *ret); extern struct parser_state *asm_parser_get_state(struct ivy_asm_parser *parser); diff --git a/asm/parse/unit.c b/asm/parse/unit.c index a6b9cb0..ecfecf9 100644 --- a/asm/parse/unit.c +++ b/asm/parse/unit.c @@ -1,33 +1,247 @@ #include "parse.h" +#include +#include + +#define HASH_IDENT 0x684f633b2528fc75 +#define HASH_INDEX 0x83cf8e8f9081468b +#define HASH_RECIPIENT 0x3d0abea328337078 +#define HASH_SELECTOR 0x03b0355a1af4ac9c +#define HASH_GET 0xd4e26318faaa79f7 +#define HASH_SET 0x823b87195ce20e23 +#define HASH_PACKAGE 0x53cf3eec39cf731b struct unit_parser_state { struct parser_state s_base; + + bool s_in_attrib_list; + unsigned int s_prev_token; + unsigned int s_next_scope; + ivy_assembler_attrib_table s_next_scope_attrib; + + struct ivy_asm_token *s_attrib_name, *s_attrib_value; }; +static enum ivy_status push_attrib(struct unit_parser_state *state) +{ + uint64_t hash = b_hash_string(state->s_attrib_name->t_str); + const char *s = state->s_attrib_name->t_str; + unsigned long long v = state->s_attrib_value->t_int.uv; + + switch (hash) { + case HASH_IDENT: + if (!strcmp(s, "ident")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_IDENT] = v; + } + break; + case HASH_INDEX: + if (!strcmp(s, "index")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_INDEX] = v; + } + break; + case HASH_RECIPIENT: + if (!strcmp(s, "recipient")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_RECIPIENT] = v; + } + break; + case HASH_SELECTOR: + if (!strcmp(s, "selector")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_SELECTOR] = v; + } + break; + case HASH_GET: + if (!strcmp(s, "get")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_GET] = v; + } + break; + case HASH_SET: + if (!strcmp(s, "set")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_SET] = v; + } + break; + case HASH_PACKAGE: + if (!strcmp(s, "package")) { + state->s_next_scope_attrib[IVY_ASM_ATTRIB_PACKAGE] = v; + } + break; + default: + return IVY_ERR_BAD_SYNTAX; + } + + ivy_asm_token_destroy(state->s_attrib_name); + ivy_asm_token_destroy(state->s_attrib_value); + + state->s_attrib_name = NULL; + state->s_attrib_value = NULL; + + return IVY_OK; +} + static enum ivy_status parse_constpool(struct ivy_asm_parser* ctx, struct ivy_asm_token* tok) { - asm_parser_push_state(ctx, ASM_PARSER_CONSTPOOL); + struct unit_parser_state *state = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_NONE) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_KEYWORD; + state->s_next_scope = ASM_PARSER_CONSTPOOL; + memset(state->s_next_scope_attrib, 0x0, sizeof state->s_next_scope_attrib); return IVY_OK; } static enum ivy_status parse_import( struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) { - asm_parser_push_state(ctx, ASM_PARSER_IMPORT); + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_NONE) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_KEYWORD; + state->s_next_scope = ASM_PARSER_IMPORT; + memset(state->s_next_scope_attrib, 0x0, sizeof state->s_next_scope_attrib); return IVY_OK; } static enum ivy_status parse_block( struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) { - asm_parser_push_state(ctx, ASM_PARSER_BLOCK); + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_NONE) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_KEYWORD; + state->s_next_scope = ASM_PARSER_BLOCK; + memset(state->s_next_scope_attrib, 0x0, sizeof state->s_next_scope_attrib); return IVY_OK; } static enum ivy_status parse_class( struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) { - asm_parser_push_state(ctx, ASM_PARSER_CLASS); + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_NONE) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_KEYWORD; + state->s_next_scope = ASM_PARSER_CLASS; + memset(state->s_next_scope_attrib, 0x0, sizeof state->s_next_scope_attrib); + return IVY_OK; +} + +static enum ivy_status parse_left_bracket( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_KEYWORD) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_in_attrib_list) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_in_attrib_list = true; + state->s_prev_token = IVY_ASM_SYM_LEFT_BRACKET; + + return IVY_OK; +} + +static enum ivy_status parse_right_bracket( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (!state->s_in_attrib_list) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_in_attrib_list = false; + state->s_prev_token = IVY_ASM_SYM_RIGHT_BRACKET; + + return IVY_OK; +} + +static enum ivy_status parse_label( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_SYM_LEFT_BRACKET && state->s_prev_token != IVY_ASM_TOK_INT) { + return IVY_ERR_BAD_SYNTAX; + } + + if (!state->s_in_attrib_list) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_attrib_name) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_prev_token = IVY_ASM_TOK_LABEL; + state->s_attrib_name = tok; + return IVY_OK; +} + +static enum ivy_status parse_int( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_prev_token != IVY_ASM_TOK_LABEL) { + return IVY_ERR_BAD_SYNTAX; + } + + if (!state->s_in_attrib_list) { + return IVY_ERR_BAD_SYNTAX; + } + + if (state->s_attrib_value) { + return IVY_ERR_BAD_SYNTAX; + } + + state->s_attrib_value = tok; + state->s_prev_token = IVY_ASM_TOK_INT; + return push_attrib(state); +} + +static enum ivy_status parse_linefeed( + struct ivy_asm_parser *ctx, struct ivy_asm_token *tok) +{ + struct unit_parser_state *state + = (struct unit_parser_state *)asm_parser_get_state(ctx); + + if (state->s_in_attrib_list) { + return IVY_OK; + } + + if (state->s_prev_token != IVY_ASM_TOK_KEYWORD && state->s_prev_token != IVY_ASM_SYM_RIGHT_BRACKET) { + return IVY_OK; + } + + if (state->s_next_scope == 0) { + return IVY_OK; + } + + asm_parser_push_state(ctx, state->s_next_scope, state->s_next_scope_attrib); + state->s_next_scope = 0; + state->s_prev_token = IVY_ASM_TOK_NONE; + return IVY_OK; } @@ -39,4 +253,13 @@ struct parser_state_type unit_parser_state_type = { KW_PARSER(CLASS, parse_class), KW_PARSER(BLOCK, parse_block), }, + .n_symbol_parsers = { + SYM_PARSER(LEFT_BRACKET, parse_left_bracket), + SYM_PARSER(RIGHT_BRACKET, parse_right_bracket), + }, + .n_token_parsers = { + TOK_PARSER(LABEL, parse_label), + TOK_PARSER(INT, parse_int), + TOK_PARSER(LINEFEED, parse_linefeed), + } }; \ No newline at end of file