mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-30 02:48:14 +03:00
jaf: support multiple input files
This commit is contained in:
@@ -334,6 +334,7 @@ int ain_get_global_no(struct ain *ain, char *name);
|
||||
void ain_add_initval(struct ain *ain, struct ain_initval *init);
|
||||
int ain_add_function(struct ain *ain, struct ain_function *fun);
|
||||
int ain_add_string(struct ain *ain, const char *str);
|
||||
int ain_add_file(struct ain *ain, const char *filename);
|
||||
|
||||
void ain_free(struct ain *ain);
|
||||
void ain_free_functions(struct ain *ain);
|
||||
|
||||
@@ -293,6 +293,13 @@ int ain_add_string(struct ain *ain, const char *str)
|
||||
return i;
|
||||
}
|
||||
|
||||
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*));
|
||||
ain->filenames[ain->nr_filenames++] = strdup(filename);
|
||||
return ain->nr_filenames - 1;
|
||||
}
|
||||
|
||||
static const char *errtab[AIN_MAX_ERROR] = {
|
||||
[AIN_SUCCESS] = "Success",
|
||||
[AIN_FILE_ERROR] = "Error opening AIN file",
|
||||
|
||||
@@ -91,7 +91,8 @@ int main(int argc, char *argv[])
|
||||
struct ain *ain;
|
||||
int err = AIN_SUCCESS;
|
||||
const char *code_file = NULL;
|
||||
const char *jaf_file = NULL;
|
||||
unsigned nr_jaf_files = 0;
|
||||
const char **jaf_files = NULL;
|
||||
const char *decl_file = NULL;
|
||||
const char *text_file = NULL;
|
||||
const char *output_file = NULL;
|
||||
@@ -133,7 +134,8 @@ int main(int argc, char *argv[])
|
||||
code_file = optarg;
|
||||
break;
|
||||
case LOPT_JAF:
|
||||
jaf_file = optarg;
|
||||
jaf_files = xrealloc_array(jaf_files, nr_jaf_files, nr_jaf_files+1, sizeof(char*));
|
||||
jaf_files[nr_jaf_files++] = optarg;
|
||||
break;
|
||||
case 'j':
|
||||
case LOPT_JSON:
|
||||
@@ -214,8 +216,8 @@ int main(int argc, char *argv[])
|
||||
read_declarations(decl_file, ain);
|
||||
}
|
||||
|
||||
if (jaf_file) {
|
||||
jaf_compile(ain, jaf_file);
|
||||
if (jaf_files) {
|
||||
jaf_build(ain, jaf_files, nr_jaf_files);
|
||||
}
|
||||
|
||||
if (code_file) {
|
||||
@@ -230,6 +232,7 @@ write_ain_file:
|
||||
NOTICE("Writing AIN file...");
|
||||
ain_write(output_file, ain);
|
||||
|
||||
free(jaf_files);
|
||||
ain_free(ain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,8 @@ enum block_item_kind {
|
||||
JAF_STMT_BREAK,
|
||||
JAF_STMT_RETURN,
|
||||
JAF_STMT_CASE,
|
||||
JAF_STMT_DEFAULT
|
||||
JAF_STMT_DEFAULT,
|
||||
JAF_EOF
|
||||
};
|
||||
|
||||
struct jaf_declaration {
|
||||
@@ -251,6 +252,7 @@ struct jaf_block_item {
|
||||
struct jaf_block_item *body;
|
||||
} for_loop;
|
||||
struct string *target; // goto
|
||||
unsigned file_no; // eof
|
||||
};
|
||||
};
|
||||
|
||||
@@ -301,6 +303,7 @@ struct jaf_block *jaf_type_declaration(struct jaf_type_specifier *type);
|
||||
struct jaf_block *jaf_merge_blocks(struct jaf_block *head, struct jaf_block *tail);
|
||||
|
||||
struct jaf_block *jaf_block(struct jaf_block_item *item);
|
||||
struct jaf_block *jaf_block_append(struct jaf_block *head, struct jaf_block_item *tail);
|
||||
struct jaf_block_item *jaf_compound_statement(struct jaf_block *block);
|
||||
struct jaf_block_item *jaf_label_statement(struct string *label, struct jaf_block_item *stmt);
|
||||
struct jaf_block_item *jaf_case_statement(struct jaf_expression *expr, struct jaf_block_item *stmt);
|
||||
@@ -318,10 +321,13 @@ struct jaf_block_item *jaf_return(struct jaf_expression *expr);
|
||||
void jaf_free_expr(struct jaf_expression *expr);
|
||||
void jaf_free_block(struct jaf_block *block);
|
||||
|
||||
// jaf_compile.c
|
||||
// jaf_parser.y
|
||||
struct ain *jaf_ain_out;
|
||||
struct jaf_block *jaf_toplevel;
|
||||
void jaf_compile(struct ain *out, const char *path);
|
||||
struct jaf_block *jaf_parse(struct ain *ain, const char **files, unsigned nr_files);
|
||||
|
||||
// jaf_compile.c
|
||||
void jaf_build(struct ain *out, const char **files, unsigned nr_files);
|
||||
void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type);
|
||||
|
||||
// jaf_eval.c
|
||||
|
||||
@@ -281,6 +281,13 @@ struct jaf_block *jaf_merge_blocks(struct jaf_block *head, struct jaf_block *tai
|
||||
return head;
|
||||
}
|
||||
|
||||
struct jaf_block *jaf_block_append(struct jaf_block *head, struct jaf_block_item *tail)
|
||||
{
|
||||
head->items = xrealloc_array(head->items, head->nr_items, head->nr_items+1, sizeof(struct jaf_block_item*));
|
||||
head->items[head->nr_items++] = tail;
|
||||
return head;
|
||||
}
|
||||
|
||||
struct jaf_block *jaf_block(struct jaf_block_item *item)
|
||||
{
|
||||
struct jaf_block *block = xcalloc(1, sizeof(struct jaf_block));
|
||||
@@ -504,6 +511,7 @@ void jaf_free_block_item(struct jaf_block_item *item)
|
||||
free_string(item->target);
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_EOF:
|
||||
break;
|
||||
case JAF_STMT_RETURN:
|
||||
jaf_free_expr(item->expr);
|
||||
|
||||
@@ -29,12 +29,6 @@
|
||||
#include "jaf.h"
|
||||
#include "jaf_parser.tab.h"
|
||||
|
||||
FILE *yyin;
|
||||
int yyparse(void);
|
||||
|
||||
struct ain *jaf_ain_out;
|
||||
struct jaf_block *jaf_toplevel;
|
||||
|
||||
/*
|
||||
* NOTE: We need to pass some state between calls to handle
|
||||
* break/continue.
|
||||
@@ -53,18 +47,6 @@ struct compiler_state {
|
||||
struct loop_state *loops;
|
||||
};
|
||||
|
||||
int sym_type(char *name)
|
||||
{
|
||||
char *u = encode_text_to_input_format(name);
|
||||
struct ain_struct *s = ain_get_struct(jaf_ain_out, u);
|
||||
free(u);
|
||||
|
||||
if (s) {
|
||||
return TYPEDEF_NAME;
|
||||
}
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
static void start_loop(struct compiler_state *state)
|
||||
{
|
||||
state->loops = xrealloc_array(state->loops, state->nr_loops, state->nr_loops+1, sizeof(struct loop_state));
|
||||
@@ -805,6 +787,9 @@ static void compile_statement(struct compiler_state *state, struct jaf_block_ite
|
||||
case JAF_STMT_DEFAULT:
|
||||
ERROR("switch not supported");
|
||||
break;
|
||||
case JAF_EOF:
|
||||
write_instruction1(state, _EOF, item->file_no);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,8 +804,8 @@ static void compile_function(struct compiler_state *state, struct jaf_declaratio
|
||||
{
|
||||
assert(decl->func_no >= 0 && decl->func_no < state->ain->nr_functions);
|
||||
state->func_no = decl->func_no;
|
||||
state->ain->functions[decl->func_no].address = state->out.index + 6;
|
||||
write_instruction1(state, FUNC, decl->func_no);
|
||||
state->ain->functions[decl->func_no].address = state->out.index;
|
||||
compile_block(state, decl->body);
|
||||
compile_nullexpr(state, state->ain->functions[state->func_no].return_type.data);
|
||||
write_instruction0(state, RETURN);
|
||||
@@ -833,6 +818,9 @@ static void compile_declaration(struct compiler_state *state, struct jaf_block_i
|
||||
compile_function(state, &decl->decl);
|
||||
return;
|
||||
}
|
||||
if (decl->kind == JAF_EOF) {
|
||||
compile_statement(state, decl);
|
||||
}
|
||||
|
||||
// TODO: global constructors/array allocations
|
||||
}
|
||||
@@ -858,58 +846,45 @@ static void compile_global_init_function(struct compiler_state *state)
|
||||
write_instruction1(state, ENDFUNC, func_no);
|
||||
}
|
||||
|
||||
void jaf_compile(struct ain *out, const char *path)
|
||||
static void jaf_compile(struct ain *ain, struct jaf_block *toplevel)
|
||||
{
|
||||
out->keycode = 0x2d1f2904;
|
||||
if (path) {
|
||||
if (!strcmp(path, "-"))
|
||||
yyin = stdin;
|
||||
else
|
||||
yyin = fopen(path, "rb");
|
||||
if (!yyin)
|
||||
ERROR("Opening input file '%s': %s", path, strerror(errno));
|
||||
}
|
||||
jaf_ain_out = out;
|
||||
yyparse();
|
||||
|
||||
if (!jaf_toplevel)
|
||||
ERROR("Failed to parse .jaf file");
|
||||
|
||||
jaf_toplevel = jaf_static_analyze(out, jaf_toplevel);
|
||||
|
||||
assert(toplevel->nr_items > 0);
|
||||
struct compiler_state state = {
|
||||
.ain = out,
|
||||
.ain = ain,
|
||||
.out = {
|
||||
.buf = out->code,
|
||||
.size = out->code_size,
|
||||
.index = out->code_size
|
||||
.buf = ain->code,
|
||||
.size = ain->code_size,
|
||||
.index = ain->code_size
|
||||
}
|
||||
};
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_items; i++) {
|
||||
compile_declaration(&state, jaf_toplevel->items[i]);
|
||||
for (size_t i = 0; i < toplevel->nr_items - 1; i++) {
|
||||
compile_declaration(&state, toplevel->items[i]);
|
||||
}
|
||||
compile_global_init_function(&state);
|
||||
|
||||
state.ain->functions[0].address = state.out.index + 6;
|
||||
// add NULL function
|
||||
write_instruction1(&state, FUNC, 0);
|
||||
write_instruction1(&state, _EOF, out->nr_filenames);
|
||||
state.ain->functions[0].address = state.out.index;
|
||||
|
||||
// add filename to ain file
|
||||
char *filename = strdup(path);
|
||||
out->filenames = xrealloc_array(out->filenames, out->nr_filenames, out->nr_filenames+1, sizeof(char*));
|
||||
out->filenames[out->nr_filenames++] = strdup(basename(filename));
|
||||
free(filename);
|
||||
// add final EOF
|
||||
compile_declaration(&state, toplevel->items[toplevel->nr_items-1]);
|
||||
|
||||
free(state.loops);
|
||||
out->code = state.out.buf;
|
||||
out->code_size = state.out.index;
|
||||
ain->code = state.out.buf;
|
||||
ain->code_size = state.out.index;
|
||||
|
||||
// XXX: ain_add_initval adds initval to GSET section of the ain file.
|
||||
// If the original ain file did not have a GSET section, init
|
||||
// code needs to be added to the "0" function instead.
|
||||
if (out->nr_initvals && !out->GSET.present) {
|
||||
WARNING("%d global initvals ignored", out->nr_initvals);
|
||||
}
|
||||
if (ain->nr_initvals && !ain->GSET.present)
|
||||
WARNING("%d global initvals ignored", ain->nr_initvals);
|
||||
}
|
||||
|
||||
jaf_free_block(jaf_toplevel);
|
||||
void jaf_build(struct ain *out, const char **files, unsigned nr_files)
|
||||
{
|
||||
struct jaf_block *toplevel;
|
||||
toplevel = jaf_parse(out, files, nr_files);
|
||||
toplevel = jaf_static_analyze(out, toplevel);
|
||||
jaf_compile(out, toplevel);
|
||||
jaf_free_block(toplevel);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,82 @@
|
||||
*/
|
||||
|
||||
%{
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "ainedit.h"
|
||||
#include "jaf.h"
|
||||
#include "jaf_parser.tab.h"
|
||||
extern int yylex();
|
||||
void yyerror(const char *s);
|
||||
int yyparse(void);
|
||||
FILE *yyin;
|
||||
|
||||
struct ain *jaf_ain_out;
|
||||
struct jaf_block *jaf_toplevel;
|
||||
|
||||
static FILE *open_jaf_file(const char *file)
|
||||
{
|
||||
if (!strcmp(file, "-"))
|
||||
return stdin;
|
||||
FILE *f = fopen(file, "rb");
|
||||
if (!f)
|
||||
ERROR("Opening input file '%s': %s", file, strerror(errno));
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct jaf_block *insert_eof(struct ain *ain, struct jaf_block *block, const char *_filename)
|
||||
{
|
||||
assert(block);
|
||||
char *filename = xstrdup(_filename);
|
||||
int file_no = ain_add_file(ain, basename(filename));
|
||||
free(filename);
|
||||
|
||||
struct jaf_block_item *eof = xmalloc(sizeof(struct jaf_block_item));
|
||||
eof->kind = JAF_EOF;
|
||||
eof->file_no = file_no;
|
||||
return jaf_block_append(block, eof);
|
||||
}
|
||||
|
||||
struct jaf_block *jaf_parse(struct ain *ain, const char **files, unsigned nr_files)
|
||||
{
|
||||
jaf_ain_out = ain;
|
||||
jaf_toplevel = NULL;
|
||||
|
||||
for (unsigned i = 0; i < nr_files; i++) {
|
||||
// open file
|
||||
yyin = open_jaf_file(files[i]);
|
||||
if (yyparse())
|
||||
ERROR("Failed to parse .jaf file");
|
||||
if (yyin != stdin)
|
||||
fclose(yyin);
|
||||
|
||||
jaf_toplevel = insert_eof(ain, jaf_toplevel, files[i]);
|
||||
}
|
||||
|
||||
struct jaf_block *r = jaf_toplevel;
|
||||
jaf_toplevel = NULL;
|
||||
jaf_ain_out = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
int sym_type(char *name)
|
||||
{
|
||||
char *u = encode_text_to_input_format(name);
|
||||
struct ain_struct *s = ain_get_struct(jaf_ain_out, u);
|
||||
free(u);
|
||||
|
||||
if (s) {
|
||||
return TYPEDEF_NAME;
|
||||
}
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
@@ -421,7 +492,7 @@ jump_statement
|
||||
;
|
||||
|
||||
toplevel
|
||||
: translation_unit { jaf_toplevel = $1; }
|
||||
: translation_unit { jaf_toplevel = jaf_merge_blocks(jaf_toplevel, $1); }
|
||||
;
|
||||
|
||||
translation_unit
|
||||
|
||||
@@ -261,6 +261,7 @@ static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item)
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_EOF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -347,6 +348,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_EOF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -429,6 +431,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_EOF:
|
||||
break;
|
||||
|
||||
case JAF_FUNDECL:
|
||||
@@ -492,7 +495,7 @@ static void jaf_process_declarations(struct ain *ain, struct jaf_block *block)
|
||||
if (block->items[i]->decl.name) {
|
||||
if (block->items[i]->kind == JAF_FUNDECL)
|
||||
add_function(ain, &block->items[i]->decl);
|
||||
else
|
||||
else if (block->items[i]->kind == JAF_DECLARATION)
|
||||
add_global(ain, &block->items[i]->decl);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user