From d3928c774d4ce5f9bb9cea940ef0a44e8b7030d3 Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Sun, 5 Jul 2020 21:54:57 -0700 Subject: [PATCH] jaf: messages and char constants --- include/system4/ain.h | 1 + src/ain.c | 7 +++++ src/tools/ainedit/jaf.h | 9 ++++++ src/tools/ainedit/jaf_ast.c | 29 ++++++++++++++++++++ src/tools/ainedit/jaf_compile.c | 14 ++++++++++ src/tools/ainedit/jaf_eval.c | 30 ++++++++++++++++++++ src/tools/ainedit/jaf_lexer.l | 2 +- src/tools/ainedit/jaf_parser.y | 11 ++++++-- src/tools/ainedit/jaf_static_analysis.c | 32 ++++++++++++++++++++++ src/tools/ainedit/jaf_types.c | 1 + src/tools/ainedit/test/array-multi.jaf | 6 ++++ src/tools/ainedit/test/char-constant.jaf | 4 +++ src/tools/ainedit/test/message-call.jaf | 16 +++++++++++ src/tools/ainedit/test/message.jaf | 12 ++++++++ src/tools/ainedit/test/run-tests.sh | 5 ++++ src/tools/ainedit/test/string-constant.jaf | 5 ++++ 16 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 src/tools/ainedit/test/array-multi.jaf create mode 100644 src/tools/ainedit/test/char-constant.jaf create mode 100644 src/tools/ainedit/test/message-call.jaf create mode 100644 src/tools/ainedit/test/message.jaf create mode 100644 src/tools/ainedit/test/string-constant.jaf diff --git a/include/system4/ain.h b/include/system4/ain.h index b37808a..0fffbe4 100644 --- a/include/system4/ain.h +++ b/include/system4/ain.h @@ -343,6 +343,7 @@ int ain_add_function(struct ain *ain, struct ain_function *fun); int ain_add_functype(struct ain *ain, struct ain_function_type *fun); int ain_get_functype(struct ain *ain, const char *name); int ain_add_string(struct ain *ain, const char *str); +int ain_add_message(struct ain *ain, const char *str); int ain_add_file(struct ain *ain, const char *filename); void ain_free(struct ain *ain); diff --git a/src/ain.c b/src/ain.c index ffa5ebf..a716491 100644 --- a/src/ain.c +++ b/src/ain.c @@ -311,6 +311,13 @@ int ain_add_string(struct ain *ain, const char *str) return i; } +int ain_add_message(struct ain *ain, const char *str) +{ + ain->messages = xrealloc_array(ain->messages, ain->nr_messages, ain->nr_messages+1, sizeof(struct string*)); + ain->messages[ain->nr_messages++] = make_string(str, strlen(str)); + return ain->nr_messages - 1; +} + int ain_add_file(struct ain *ain, const char *filename) { ain->filenames = xrealloc_array(ain->filenames, ain->nr_filenames, ain->nr_filenames+1, sizeof(char*)); diff --git a/src/tools/ainedit/jaf.h b/src/tools/ainedit/jaf.h index 0b32657..27961dc 100644 --- a/src/tools/ainedit/jaf.h +++ b/src/tools/ainedit/jaf.h @@ -56,6 +56,7 @@ enum jaf_expression_type { JAF_EXP_MEMBER, JAF_EXP_SEQ, JAF_EXP_SUBSCRIPT, + JAF_EXP_CHAR, }; enum jaf_operator { @@ -211,6 +212,7 @@ enum block_item_kind { JAF_STMT_RETURN, JAF_STMT_CASE, JAF_STMT_DEFAULT, + JAF_STMT_MESSAGE, JAF_EOF }; @@ -266,6 +268,11 @@ struct jaf_block_item { struct jaf_expression *after; struct jaf_block_item *body; } for_loop; + struct { + struct string *text; + struct string *func; + int func_no; + } msg; struct string *target; // goto unsigned file_no; // eof }; @@ -291,6 +298,7 @@ struct jaf_expression *jaf_float(float f); struct jaf_expression *jaf_parse_float(struct string *text); struct string *jaf_process_string(struct string *text); struct jaf_expression *jaf_string(struct string *text); +struct jaf_expression *jaf_char(struct string *text); struct jaf_expression *jaf_identifier(struct string *name); struct jaf_expression *jaf_unary_expr(enum jaf_operator op, struct jaf_expression *expr); struct jaf_expression *jaf_binary_expr(enum jaf_operator op, struct jaf_expression *lhs, struct jaf_expression *rhs); @@ -339,6 +347,7 @@ struct jaf_block_item *jaf_goto(struct string *target); struct jaf_block_item *jaf_continue(void); struct jaf_block_item *jaf_break(void); struct jaf_block_item *jaf_return(struct jaf_expression *expr); +struct jaf_block_item *jaf_message_statement(struct string *msg, struct string *func); void jaf_free_expr(struct jaf_expression *expr); void jaf_free_block(struct jaf_block *block); diff --git a/src/tools/ainedit/jaf_ast.c b/src/tools/ainedit/jaf_ast.c index 80e9cea..2631239 100644 --- a/src/tools/ainedit/jaf_ast.c +++ b/src/tools/ainedit/jaf_ast.c @@ -104,6 +104,14 @@ struct jaf_expression *jaf_string(struct string *text) return e; } +struct jaf_expression *jaf_char(struct string *text) +{ + struct jaf_expression *e = jaf_expr(JAF_EXP_CHAR, 0); + e->valuetype.data = AIN_INT; + e->s = text; + return e; +} + struct jaf_expression *jaf_identifier(struct string *name) { struct jaf_expression *e = jaf_expr(JAF_EXP_IDENTIFIER, 0); @@ -445,8 +453,23 @@ struct jaf_block_item *jaf_case_statement(struct jaf_expression *expr, struct ja return item; } +struct jaf_block_item *jaf_message_statement(struct string *msg, struct string *func) +{ + struct jaf_block_item *item = block_item(JAF_STMT_MESSAGE); + item->msg.text = msg; + item->msg.func = func; + return item; +} + struct jaf_block_item *jaf_expression_statement(struct jaf_expression *expr) { + // NOTE: character constant as statement is treated as a message + if (expr->type == JAF_EXP_CHAR) { + struct string *s = expr->s; + free(expr); + return jaf_message_statement(s, NULL); + } + struct jaf_block_item *item = block_item(JAF_STMT_EXPRESSION); item->expr = expr; return item; @@ -531,6 +554,7 @@ void jaf_free_expr(struct jaf_expression *expr) case JAF_EXP_FLOAT: break; case JAF_EXP_STRING: + case JAF_EXP_CHAR: case JAF_EXP_IDENTIFIER: free_string(expr->s); break; @@ -659,6 +683,11 @@ void jaf_free_block_item(struct jaf_block_item *item) jaf_free_expr(item->swi_case.expr); jaf_free_block_item(item->swi_case.stmt); break; + case JAF_STMT_MESSAGE: + free_string(item->msg.text); + if (item->msg.func) + free_string(item->msg.func); + break; } free(item); } diff --git a/src/tools/ainedit/jaf_compile.c b/src/tools/ainedit/jaf_compile.c index f32c668..4da5077 100644 --- a/src/tools/ainedit/jaf_compile.c +++ b/src/tools/ainedit/jaf_compile.c @@ -617,6 +617,9 @@ static void compile_expression(struct compiler_state *state, struct jaf_expressi case JAF_EXP_SUBSCRIPT: compile_subscript(state, expr); break; + case JAF_EXP_CHAR: + ERROR("Unresolved character constant"); // should have been simplified to int + break; } } @@ -887,6 +890,14 @@ static void compile_break(struct compiler_state *state) write_instruction1(state, JUMP, 0); } +static void compile_message(struct compiler_state *state, struct jaf_block_item *item) +{ + int no = ain_add_message(state->ain, item->msg.text->text); + write_instruction1(state, MSG, no); + if (item->msg.func) + write_instruction1(state, CALLFUNC, item->msg.func_no); +} + static void compile_statement(struct compiler_state *state, struct jaf_block_item *item) { switch (item->kind) { @@ -942,6 +953,9 @@ static void compile_statement(struct compiler_state *state, struct jaf_block_ite case JAF_STMT_DEFAULT: ERROR("switch not supported"); break; + case JAF_STMT_MESSAGE: + compile_message(state, item); + break; case JAF_EOF: write_instruction1(state, _EOF, item->file_no); break; diff --git a/src/tools/ainedit/jaf_eval.c b/src/tools/ainedit/jaf_eval.c index 493a1a8..a1530a3 100644 --- a/src/tools/ainedit/jaf_eval.c +++ b/src/tools/ainedit/jaf_eval.c @@ -341,6 +341,34 @@ static struct jaf_expression *jaf_simplify_subscript(struct jaf_expression *in) return in; } +static struct jaf_expression *jaf_simplify_char(struct jaf_expression *in) +{ + int c = 0; + int size = in->s->size; + char *s = in->s->text; + if (size <= 0) + goto invalid; + if (s[0] == '\\') { + if (size != 2) + goto invalid; + switch (s[1]) { + case '\\': c = '\\'; goto valid; + case '\'': c = '\''; goto valid; + default: goto invalid; + } + } + if (size != 1) + goto invalid; + c = s[0]; +valid: + free_string(in->s); + in->type = JAF_EXP_INT; + in->i = c; + return in; +invalid: + ERROR("Invalid character constant"); +} + /* * Simplify an expression by evaluating the constant parts. */ @@ -370,6 +398,8 @@ struct jaf_expression *jaf_simplify(struct jaf_expression *in) return jaf_simplify_seq(in); case JAF_EXP_SUBSCRIPT: return jaf_simplify_subscript(in); + case JAF_EXP_CHAR: + return jaf_simplify_char(in); } ERROR("Invalid expression type"); } diff --git a/src/tools/ainedit/jaf_lexer.l b/src/tools/ainedit/jaf_lexer.l index 73eeb4d..5b31525 100644 --- a/src/tools/ainedit/jaf_lexer.l +++ b/src/tools/ainedit/jaf_lexer.l @@ -97,7 +97,7 @@ unsigned long jaf_line = 1; {HP}{H}+{IS}? { RETURN_STRING(I_CONSTANT); } {NZ}{D}*{IS}? { RETURN_STRING(I_CONSTANT); } "0"{O}*{IS}? { RETURN_STRING(I_CONSTANT); } -"'"([^'\\\n]|{ES})+"'" { RETURN_STRING(I_CONSTANT); } +"'"([^'\\\n]|{ES})+"'" { yylval.string = make_string(yytext+1, yyleng-2); return C_CONSTANT; } {D}+{E}{FS}? { RETURN_STRING(F_CONSTANT); } {D}*"."{D}+{E}?{FS}? { RETURN_STRING(F_CONSTANT); } diff --git a/src/tools/ainedit/jaf_parser.y b/src/tools/ainedit/jaf_parser.y index 1a1de7d..630b154 100644 --- a/src/tools/ainedit/jaf_parser.y +++ b/src/tools/ainedit/jaf_parser.y @@ -155,7 +155,7 @@ static struct string *time_macro(void) struct jaf_function_declarator *fundecl; } -%token I_CONSTANT F_CONSTANT STRING_LITERAL +%token I_CONSTANT F_CONSTANT C_CONSTANT STRING_LITERAL %token IDENTIFIER TYPEDEF_NAME ENUMERATION_CONSTANT %token INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP @@ -191,7 +191,7 @@ static struct string *time_macro(void) %type functype_parameter_list functype_parameter_declaration %type compound_statement block_item_list block_item %type statement labeled_statement expression_statement selection_statement -%type iteration_statement jump_statement +%type iteration_statement jump_statement message_statement %type function_declarator functype_declarator /* @@ -200,7 +200,6 @@ static struct string *time_macro(void) * 2. functype vs global */ %expect 1 -%precedence FUNCTYPE %start toplevel %% @@ -214,6 +213,7 @@ primary_expression constant : I_CONSTANT { $$ = jaf_parse_integer($1); } /* includes character_constant */ + | C_CONSTANT { $$ = jaf_char($1); } | F_CONSTANT { $$ = jaf_parse_float($1); } | ENUMERATION_CONSTANT { ERROR("Enums not supported"); } /* after it has been defined as such */ ; @@ -499,6 +499,7 @@ statement | selection_statement { $$ = $1; } | iteration_statement { $$ = $1; } | jump_statement { $$ = $1; } + | message_statement { $$ = $1; } ; labeled_statement @@ -550,6 +551,10 @@ jump_statement | SYM_RETURN expression ';' { $$ = jaf_return($2); } ; +message_statement + : C_CONSTANT IDENTIFIER ';' { $$ = jaf_message_statement($1, $2); } + ; + toplevel : translation_unit { jaf_toplevel = jaf_merge_blocks(jaf_toplevel, $1); } ; diff --git a/src/tools/ainedit/jaf_static_analysis.c b/src/tools/ainedit/jaf_static_analysis.c index 1c95920..9262f20 100644 --- a/src/tools/ainedit/jaf_static_analysis.c +++ b/src/tools/ainedit/jaf_static_analysis.c @@ -241,6 +241,19 @@ static void analyze_function(struct jaf_env *env, struct jaf_declaration *decl) free(funenv); } +static void analyze_message(struct jaf_env *env, struct jaf_block_item *item) +{ + if (!item->msg.func) { + item->msg.func_no = -1; + return; + } + + char *u = encode_text_to_input_format(item->msg.func->text); + if ((item->msg.func_no = ain_get_function_no(env->ain, u)) < 0) + ERROR("Undefined function: %s", item->msg.func->text); + free(u); +} + static struct jaf_env *push_env(struct jaf_env *parent) { struct jaf_env *newenv = xcalloc(1, sizeof(struct jaf_env)); @@ -313,6 +326,8 @@ static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item) case JAF_STMT_DEFAULT: analyze_statement(env, item->swi_case.stmt); break; + case JAF_STMT_MESSAGE: + analyze_message(env, item); case JAF_FUNCTYPE_DECL: case JAF_STMT_GOTO: case JAF_STMT_CONTINUE: @@ -408,6 +423,7 @@ static void resolve_statement_types(struct ain *ain, struct jaf_block_item *item case JAF_STMT_CONTINUE: case JAF_STMT_BREAK: case JAF_STMT_RETURN: + case JAF_STMT_MESSAGE: case JAF_EOF: break; } @@ -492,6 +508,7 @@ static struct ain_variable *block_item_get_vars(struct ain *ain, struct jaf_bloc case JAF_STMT_CONTINUE: case JAF_STMT_BREAK: case JAF_STMT_RETURN: + case JAF_STMT_MESSAGE: case JAF_EOF: break; @@ -539,6 +556,21 @@ static void add_function(struct ain *ain, struct jaf_declaration *decl) if (ain->main > 0) WARNING("Overriding main function"); ain->main = decl->func_no; + } else if (!strcmp(decl->name->text, "message")) { + if (!decl->params || + decl->params->nr_items != 3 || + decl->params->items[0]->decl.type->type != JAF_INT || + decl->params->items[0]->decl.type->qualifiers || + decl->params->items[1]->decl.type->type != JAF_INT || + decl->params->items[1]->decl.type->qualifiers || + decl->params->items[2]->decl.type->type != JAF_STRING || + decl->params->items[2]->decl.type->qualifiers || + decl->type->type != JAF_VOID) { + ERROR("Invalid signature for message function"); + } + if (ain->msgf > 0) + WARNING("Overriding message function"); + ain->msgf = decl->func_no; } } diff --git a/src/tools/ainedit/jaf_types.c b/src/tools/ainedit/jaf_types.c index 4264be9..ad1ceca 100644 --- a/src/tools/ainedit/jaf_types.c +++ b/src/tools/ainedit/jaf_types.c @@ -540,6 +540,7 @@ void jaf_derive_types(struct jaf_env *env, struct jaf_expression *expr) expr->valuetype.data = AIN_VOID; break; case JAF_EXP_INT: + case JAF_EXP_CHAR: expr->valuetype.data = AIN_INT; break; case JAF_EXP_FLOAT: diff --git a/src/tools/ainedit/test/array-multi.jaf b/src/tools/ainedit/test/array-multi.jaf new file mode 100644 index 0000000..18a788a --- /dev/null +++ b/src/tools/ainedit/test/array-multi.jaf @@ -0,0 +1,6 @@ +int main() +{ + array@int@2 a[1][2]; + a[0][1] = 1; + return !(a[0][1] == 1); +} diff --git a/src/tools/ainedit/test/char-constant.jaf b/src/tools/ainedit/test/char-constant.jaf new file mode 100644 index 0000000..c7d3150 --- /dev/null +++ b/src/tools/ainedit/test/char-constant.jaf @@ -0,0 +1,4 @@ +int main() +{ + return !('a' == 97); +} diff --git a/src/tools/ainedit/test/message-call.jaf b/src/tools/ainedit/test/message-call.jaf new file mode 100644 index 0000000..94641a1 --- /dev/null +++ b/src/tools/ainedit/test/message-call.jaf @@ -0,0 +1,16 @@ +int result = 0; + +void message(int n, int total, string msg) +{ +} + +void A(void) +{ + result = 1; +} + +int main() +{ + 'test' A; + return !(result == 1); +} diff --git a/src/tools/ainedit/test/message.jaf b/src/tools/ainedit/test/message.jaf new file mode 100644 index 0000000..0e82bc4 --- /dev/null +++ b/src/tools/ainedit/test/message.jaf @@ -0,0 +1,12 @@ +int result = 0; + +void message(int n, int total, string msg) +{ + result = msg == "test"; +} + +int main() +{ + 'test'; + return !(result == 1); +} diff --git a/src/tools/ainedit/test/run-tests.sh b/src/tools/ainedit/test/run-tests.sh index d0a64f2..2305a56 100755 --- a/src/tools/ainedit/test/run-tests.sh +++ b/src/tools/ainedit/test/run-tests.sh @@ -103,3 +103,8 @@ cd $(dirname "$0") ./test-runner.sh functype.jaf ./test-runner.sh functype-void.jaf ./test-runner.sh functype-ref-int.jaf + +./test-runner.sh message.jaf +./test-runner.sh message-call.jaf + +./test-runner.sh char-constant.jaf diff --git a/src/tools/ainedit/test/string-constant.jaf b/src/tools/ainedit/test/string-constant.jaf new file mode 100644 index 0000000..1112807 --- /dev/null +++ b/src/tools/ainedit/test/string-constant.jaf @@ -0,0 +1,5 @@ +int main() +{ + string a = "asdf\n" "\nfdsa"; + return !(a == "asdf\n\nfdsa"); +}