mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-12 01:08:32 +03:00
jaf: initial compiler implementation
Supports reading from local variables (no assignment) and arithmetic.
This commit is contained in:
@@ -124,7 +124,8 @@ enum ain_data_type {
|
||||
|
||||
enum ain_variable_type {
|
||||
AIN_VAR_LOCAL,
|
||||
AIN_VAR_MEMBER
|
||||
AIN_VAR_MEMBER,
|
||||
AIN_VAR_GLOBAL
|
||||
};
|
||||
|
||||
struct ain_type {
|
||||
@@ -327,6 +328,7 @@ int ain_get_struct_no(struct ain *ain, char *name);
|
||||
int ain_add_struct(struct ain *ain, char *name);
|
||||
struct ain_variable *ain_add_global(struct ain *ain, char *name);
|
||||
struct ain_variable *ain_get_global(struct ain *ain, char *name);
|
||||
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);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ char *buffer_strdata(struct buffer *r);
|
||||
|
||||
void buffer_write_int32(struct buffer *b, uint32_t v);
|
||||
void buffer_write_int32_at(struct buffer *buf, size_t index, uint32_t v);
|
||||
void buffer_write_int16(struct buffer *b, uint16_t v);
|
||||
void buffer_write_float(struct buffer *b, float f);
|
||||
void buffer_write_bytes(struct buffer *b, const uint8_t *bytes, size_t len);
|
||||
void buffer_write_string(struct buffer *b, struct string *s);
|
||||
|
||||
@@ -223,6 +223,7 @@ struct ain_variable *ain_add_global(struct ain *ain, char *name)
|
||||
ain->globals[no].name = strdup(name);
|
||||
if (ain->version >= 12)
|
||||
ain->globals[no].name2 = strdup("");
|
||||
ain->globals[no].var_type = AIN_VAR_GLOBAL;
|
||||
ain->nr_globals++;
|
||||
return &ain->globals[no];
|
||||
}
|
||||
@@ -237,6 +238,12 @@ struct ain_variable *ain_get_global(struct ain *ain, char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ain_get_global_no(struct ain *ain, char *name)
|
||||
{
|
||||
struct ain_variable *v = ain_get_global(ain, name);
|
||||
return v ? v - ain->globals : -1;
|
||||
}
|
||||
|
||||
void ain_add_initval(struct ain *ain, struct ain_initval *init)
|
||||
{
|
||||
ain->global_initvals = xrealloc_array(ain->global_initvals, ain->nr_initvals, ain->nr_initvals+1,
|
||||
@@ -629,6 +636,7 @@ static struct ain_variable *read_globals(struct ain_reader *r, int count, struct
|
||||
read_variable_type(r, &globals[i].type);
|
||||
if (ain->version >= 5)
|
||||
globals[i].group_index = read_int32(r);
|
||||
globals[i].var_type = AIN_VAR_GLOBAL;
|
||||
}
|
||||
return globals;
|
||||
}
|
||||
|
||||
@@ -113,6 +113,13 @@ void buffer_write_int32_at(struct buffer *buf, size_t index, uint32_t v)
|
||||
buf->index = tmp;
|
||||
}
|
||||
|
||||
void buffer_write_int16(struct buffer *b, uint16_t v)
|
||||
{
|
||||
alloc_buffer(b, 2);
|
||||
b->buf[b->index++] = (v & 0x00FF);
|
||||
b->buf[b->index++] = (v & 0xFF00) >> 8;
|
||||
}
|
||||
|
||||
void buffer_write_float(struct buffer *b, float f)
|
||||
{
|
||||
union { float f; uint32_t u; } v;
|
||||
|
||||
+12
-3
@@ -35,8 +35,9 @@ enum jaf_type {
|
||||
};
|
||||
|
||||
enum jaf_type_qualifier {
|
||||
JAF_QUAL_CONST = 1,
|
||||
JAF_QUAL_REF = 2
|
||||
JAF_QUAL_CONST = 1,
|
||||
JAF_QUAL_REF = 2,
|
||||
JAF_QUAL_GLOBAL = 4,
|
||||
};
|
||||
|
||||
enum jaf_expression_type {
|
||||
@@ -122,6 +123,11 @@ struct jaf_expression {
|
||||
int i;
|
||||
float f;
|
||||
struct string *s;
|
||||
struct {
|
||||
struct string *name;
|
||||
enum ain_variable_type var_type;
|
||||
int var_no;
|
||||
} ident;
|
||||
// unary operators
|
||||
struct jaf_expression *expr;
|
||||
// binary operators
|
||||
@@ -315,13 +321,16 @@ struct ain *jaf_ain_out;
|
||||
struct jaf_block *jaf_toplevel;
|
||||
void jaf_compile(struct ain *out, const char *path);
|
||||
void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type);
|
||||
struct ain_variable *jaf_env_lookup(struct jaf_env *env, struct string *name);
|
||||
|
||||
// jaf_eval.c
|
||||
struct jaf_expression *jaf_simplify(struct jaf_expression *in);
|
||||
|
||||
// jaf_types.c
|
||||
const char *jaf_typestr(enum jaf_type type);
|
||||
void jaf_derive_types(struct jaf_env *env, struct jaf_expression *expr);
|
||||
void jaf_check_type(struct jaf_expression *expr, struct jaf_type_specifier *type);
|
||||
|
||||
// jaf_static_analysis.c
|
||||
struct jaf_block *jaf_static_analyze(struct ain *ain, struct jaf_block *block);
|
||||
|
||||
#endif /* AINEDIT_JAF_H */
|
||||
|
||||
@@ -79,7 +79,7 @@ struct jaf_expression *jaf_string(struct string *text)
|
||||
struct jaf_expression *jaf_identifier(struct string *name)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_IDENTIFIER, 0);
|
||||
e->s = name;
|
||||
e->ident.name = name;
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ struct jaf_expression *jaf_cast_expression(enum jaf_type type, struct jaf_expres
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_CAST, 0);
|
||||
e->cast.type = type;
|
||||
e->cast.expr = expr;
|
||||
e->value_type.type = type;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
+363
-391
@@ -21,6 +21,8 @@
|
||||
#include <assert.h>
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "system4/buffer.h"
|
||||
#include "system4/instructions.h"
|
||||
#include "system4/string.h"
|
||||
#include "ainedit.h"
|
||||
#include "jaf.h"
|
||||
@@ -44,438 +46,418 @@ int sym_type(char *name)
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
static void define_types(struct ain *ain, struct jaf_block_item *decl);
|
||||
|
||||
void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type)
|
||||
static void write_opcode(struct buffer *out, uint16_t opcode)
|
||||
{
|
||||
if (!type->name)
|
||||
ERROR("Anonymous structs not supported");
|
||||
|
||||
char *u = encode_text_to_input_format(type->name->text);
|
||||
if (ain_get_struct(ain, u)) {
|
||||
ERROR("Redefining structs not supported");
|
||||
}
|
||||
|
||||
type->struct_no = ain_add_struct(ain, u);
|
||||
free(u);
|
||||
|
||||
for (size_t i = 0; i < type->def->nr_items; i++) {
|
||||
define_types(ain, type->def->items[i]);
|
||||
}
|
||||
buffer_write_int16(out, opcode);
|
||||
}
|
||||
|
||||
static void define_types(struct ain *ain, struct jaf_block_item *decl)
|
||||
static void write_argument(struct buffer *out, uint32_t arg)
|
||||
{
|
||||
if (!decl)
|
||||
ERROR("DECL IS NULL");
|
||||
if (!decl->decl.type)
|
||||
ERROR("TYPE IS NULL");
|
||||
if (decl->decl.type->type != JAF_STRUCT)
|
||||
return;
|
||||
|
||||
jaf_define_struct(ain, decl->decl.type);
|
||||
buffer_write_int32(out, arg);
|
||||
}
|
||||
|
||||
static enum ain_data_type jaf_to_ain_data_type(enum jaf_type type)
|
||||
static void write_instruction0(struct buffer *out, uint16_t opcode)
|
||||
{
|
||||
switch (type) {
|
||||
case JAF_VOID: return AIN_VOID;
|
||||
case JAF_INT: return AIN_INT;
|
||||
case JAF_FLOAT: return AIN_FLOAT;
|
||||
case JAF_STRING: return AIN_STRING;
|
||||
case JAF_STRUCT: return AIN_STRUCT;
|
||||
case JAF_ENUM: ERROR("Enums not supported");
|
||||
default: ERROR("Unknown type: %d", type);
|
||||
}
|
||||
write_opcode(out, opcode);
|
||||
}
|
||||
|
||||
static void jaf_to_ain_type(possibly_unused struct ain *ain, struct ain_type *out, struct jaf_type_specifier *in)
|
||||
static void write_instruction1(struct buffer *out, uint16_t opcode, uint32_t arg0)
|
||||
{
|
||||
out->data = jaf_to_ain_data_type(in->type);
|
||||
if (in->type == JAF_STRUCT) {
|
||||
out->struc = in->struct_no;
|
||||
}
|
||||
write_opcode(out, opcode);
|
||||
write_argument(out, arg0);
|
||||
}
|
||||
|
||||
static void resolve_typedef(struct ain *ain, struct jaf_type_specifier *type)
|
||||
static void write_instruction2(struct buffer *out, uint16_t opcode, uint32_t arg0, uint32_t arg1)
|
||||
{
|
||||
char *u = encode_text_to_input_format(type->name->text);
|
||||
int sno = ain_get_struct_no(ain, u);
|
||||
if (sno) {
|
||||
type->type = JAF_STRUCT;
|
||||
type->struct_no = sno;
|
||||
write_opcode(out, opcode);
|
||||
write_argument(out, arg0);
|
||||
write_argument(out, arg1);
|
||||
}
|
||||
|
||||
static uint32_t flo2int(float f)
|
||||
{
|
||||
union { uint32_t i; float f; } v = { .f = f};
|
||||
return v.i;
|
||||
}
|
||||
|
||||
static enum opcode jaf_op_to_opcode(enum jaf_operator op, enum jaf_type type)
|
||||
{
|
||||
if (type == JAF_FLOAT) {
|
||||
switch (op) {
|
||||
case JAF_MULTIPLY: return F_MUL;
|
||||
case JAF_DIVIDE: return F_DIV;
|
||||
case JAF_PLUS: return F_ADD;
|
||||
case JAF_MINUS: return F_SUB;
|
||||
case JAF_LT: return F_LT;
|
||||
case JAF_GT: return F_GT;
|
||||
case JAF_LTE: return F_LTE;
|
||||
case JAF_GTE: return F_GTE;
|
||||
case JAF_EQ: return F_EQUALE;
|
||||
case JAF_ASSIGN: return F_ASSIGN;
|
||||
case JAF_MUL_ASSIGN: return F_MULA;
|
||||
case JAF_DIV_ASSIGN: return F_DIVA;
|
||||
case JAF_ADD_ASSIGN: return F_PLUSA;
|
||||
case JAF_SUB_ASSIGN: return F_MINUSA;
|
||||
case JAF_REF_ASSIGN: // TODO
|
||||
default: ERROR("Invalid floating point operator");
|
||||
}
|
||||
} else if (type == JAF_INT) {
|
||||
switch (op) {
|
||||
case JAF_MULTIPLY: return MUL;
|
||||
case JAF_DIVIDE: return DIV;
|
||||
case JAF_REMAINDER: return MOD;
|
||||
case JAF_PLUS: return ADD;
|
||||
case JAF_MINUS: return SUB;
|
||||
case JAF_LSHIFT: return LSHIFT;
|
||||
case JAF_RSHIFT: return RSHIFT;
|
||||
case JAF_LT: return LT;
|
||||
case JAF_GT: return GT;
|
||||
case JAF_LTE: return LTE;
|
||||
case JAF_GTE: return GTE;
|
||||
case JAF_EQ: return EQUALE;
|
||||
case JAF_BIT_AND: return AND;
|
||||
case JAF_BIT_XOR: return XOR;
|
||||
case JAF_BIT_IOR: return OR;
|
||||
//case JAF_LOG_AND: return AND;
|
||||
//case JAF_LOG_OR: return OR;
|
||||
case JAF_ASSIGN: return ASSIGN;
|
||||
case JAF_MUL_ASSIGN: return MULA;
|
||||
case JAF_DIV_ASSIGN: return DIVA;
|
||||
case JAF_MOD_ASSIGN: return MODA;
|
||||
case JAF_ADD_ASSIGN: return PLUSA;
|
||||
case JAF_SUB_ASSIGN: return MINUSA;
|
||||
case JAF_LSHIFT_ASSIGN: return LSHIFTA;
|
||||
case JAF_RSHIFT_ASSIGN: return RSHIFTA;
|
||||
case JAF_AND_ASSIGN: return ANDA;
|
||||
case JAF_XOR_ASSIGN: return XORA;
|
||||
case JAF_OR_ASSIGN: return ORA;
|
||||
case JAF_REF_ASSIGN: // TODO
|
||||
default: ERROR("Invalid integer operator");
|
||||
}
|
||||
} else {
|
||||
ERROR("Failed to resolve typedef \"%s\"", type->name->text);
|
||||
ERROR("Invalid operator type");
|
||||
}
|
||||
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void jaf_to_initval(struct ain_initval *dst, struct jaf_expression *expr)
|
||||
static void compile_block(struct ain *ain, struct buffer *out, struct jaf_block *block);
|
||||
static void compile_expression(struct ain *ain, struct buffer *out, struct jaf_expression *expr);
|
||||
|
||||
static void compile_identifier(possibly_unused struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->ident.var_type == AIN_VAR_LOCAL) {
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
} else if (expr->ident.var_type == AIN_VAR_GLOBAL) {
|
||||
write_instruction0(out, PUSHGLOBALPAGE);
|
||||
} else {
|
||||
ERROR("Invalid variable type");
|
||||
}
|
||||
write_instruction1(out, PUSH, expr->ident.var_no);
|
||||
write_instruction0(out, REF);
|
||||
}
|
||||
|
||||
static void compile_unary(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->op) {
|
||||
case JAF_AMPERSAND:
|
||||
ERROR("Function types not supported");
|
||||
case JAF_UNARY_PLUS:
|
||||
compile_expression(ain, out, expr->expr);
|
||||
break;
|
||||
case JAF_UNARY_MINUS:
|
||||
write_instruction0(out, INV);
|
||||
break;
|
||||
case JAF_BIT_NOT:
|
||||
write_instruction0(out, COMPL);
|
||||
break;
|
||||
case JAF_LOG_NOT:
|
||||
write_instruction0(out, NOT);
|
||||
break;
|
||||
case JAF_PRE_INC:
|
||||
case JAF_PRE_DEC:
|
||||
case JAF_POST_INC:
|
||||
case JAF_POST_DEC:
|
||||
ERROR("Increment/decrement not supported"); // TODO: need location type
|
||||
default:
|
||||
ERROR("Invalid unary operator");
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_binary(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->op) {
|
||||
case JAF_MULTIPLY:
|
||||
case JAF_DIVIDE:
|
||||
case JAF_REMAINDER:
|
||||
case JAF_PLUS:
|
||||
case JAF_MINUS:
|
||||
case JAF_LSHIFT:
|
||||
case JAF_RSHIFT:
|
||||
case JAF_LT:
|
||||
case JAF_GT:
|
||||
case JAF_LTE:
|
||||
case JAF_GTE:
|
||||
case JAF_EQ:
|
||||
case JAF_BIT_AND:
|
||||
case JAF_BIT_XOR:
|
||||
case JAF_BIT_IOR:
|
||||
assert(expr->lhs->value_type.type == expr->rhs->value_type.type);
|
||||
compile_expression(ain, out, expr->lhs);
|
||||
compile_expression(ain, out, expr->rhs);
|
||||
write_instruction0(out, jaf_op_to_opcode(expr->op, expr->value_type.type));
|
||||
break;
|
||||
case JAF_LOG_AND:
|
||||
ERROR("Logical AND not supported");
|
||||
break;
|
||||
case JAF_LOG_OR:
|
||||
ERROR("Logical OR not supported");
|
||||
break;
|
||||
case JAF_ASSIGN:
|
||||
case JAF_MUL_ASSIGN:
|
||||
case JAF_DIV_ASSIGN:
|
||||
case JAF_MOD_ASSIGN:
|
||||
case JAF_ADD_ASSIGN:
|
||||
case JAF_SUB_ASSIGN:
|
||||
case JAF_LSHIFT_ASSIGN:
|
||||
case JAF_RSHIFT_ASSIGN:
|
||||
case JAF_AND_ASSIGN:
|
||||
case JAF_XOR_ASSIGN:
|
||||
case JAF_OR_ASSIGN:
|
||||
case JAF_REF_ASSIGN:
|
||||
ERROR("Assignment not supported");
|
||||
default:
|
||||
ERROR("Invalid binary operator");
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_ternary(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
ERROR("Ternary operator not supported");
|
||||
}
|
||||
|
||||
static void compile_funcall(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
for (size_t i = 0; i < expr->call.args->nr_items; i++) {
|
||||
compile_expression(ain, out, expr->call.args->items[i]);
|
||||
}
|
||||
write_instruction1(out, CALLFUNC, expr->call.func_no);
|
||||
}
|
||||
|
||||
static void compile_cast(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
enum jaf_type src_type = expr->cast.expr->value_type.type;
|
||||
enum jaf_type dst_type = expr->cast.type;
|
||||
compile_expression(ain, out, expr->cast.expr);
|
||||
|
||||
if (src_type == dst_type)
|
||||
return;
|
||||
if (src_type == JAF_INT) {
|
||||
if (dst_type == JAF_FLOAT) {
|
||||
write_instruction0(out, ITOF);
|
||||
} else if (dst_type == JAF_STRING) {
|
||||
write_instruction0(out, I_STRING);
|
||||
} else {
|
||||
goto invalid_cast;
|
||||
}
|
||||
} else if (src_type == JAF_FLOAT) {
|
||||
if (dst_type == JAF_INT) {
|
||||
write_instruction0(out, FTOI);
|
||||
} else if (dst_type == JAF_STRING) {
|
||||
write_instruction0(out, FTOS);
|
||||
} else {
|
||||
goto invalid_cast;
|
||||
}
|
||||
} else if (src_type == JAF_STRING) {
|
||||
if (dst_type == JAF_INT) {
|
||||
write_instruction0(out, STOI);
|
||||
} else {
|
||||
goto invalid_cast;
|
||||
}
|
||||
}
|
||||
return;
|
||||
invalid_cast:
|
||||
ERROR("Unsupported cast: %s to %s", jaf_typestr(src_type), jaf_typestr(dst_type));
|
||||
}
|
||||
|
||||
static void compile_member(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
ERROR("struct member access not supported");
|
||||
}
|
||||
|
||||
static void compile_expression(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->type) {
|
||||
case JAF_EXP_VOID:
|
||||
break;
|
||||
case JAF_EXP_INT:
|
||||
dst->data_type = AIN_INT;
|
||||
dst->int_value = expr->i;
|
||||
write_instruction1(out, PUSH, expr->i);
|
||||
break;
|
||||
case JAF_EXP_FLOAT:
|
||||
dst->data_type = AIN_FLOAT;
|
||||
dst->float_value = expr->f;
|
||||
write_instruction1(out, F_PUSH, flo2int(expr->f));
|
||||
break;
|
||||
case JAF_EXP_STRING:
|
||||
dst->data_type = AIN_STRING;
|
||||
dst->string_value = strdup(expr->s->text);
|
||||
ERROR("strings not supported");
|
||||
case JAF_EXP_IDENTIFIER:
|
||||
compile_identifier(ain, out, expr);
|
||||
break;
|
||||
default:
|
||||
ERROR("Initval is not constant");
|
||||
case JAF_EXP_UNARY:
|
||||
compile_unary(ain, out, expr);
|
||||
break;
|
||||
case JAF_EXP_BINARY:
|
||||
compile_binary(ain, out, expr);
|
||||
break;
|
||||
case JAF_EXP_TERNARY:
|
||||
compile_ternary(ain, out, expr);
|
||||
break;
|
||||
//case JAF_EXP_SUBSCRIPT:
|
||||
//compile_subscript(ain, out, expr);
|
||||
//break;
|
||||
case JAF_EXP_FUNCALL:
|
||||
compile_funcall(ain, out, expr);
|
||||
break;
|
||||
case JAF_EXP_CAST:
|
||||
compile_cast(ain, out, expr);
|
||||
break;
|
||||
case JAF_EXP_MEMBER:
|
||||
compile_member(ain, out, expr);
|
||||
break;
|
||||
//case JAF_EXP_SEQ:
|
||||
//compile_seq(ain, out, expr);
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
static void analyze_expression(struct jaf_env *env, struct jaf_expression **expr)
|
||||
static void compile_vardecl(struct ain *ain, struct buffer *out, struct jaf_declaration *decl)
|
||||
{
|
||||
if (!*expr)
|
||||
return;
|
||||
jaf_derive_types(env, *expr);
|
||||
*expr = jaf_simplify(*expr);
|
||||
}
|
||||
|
||||
static void _analyze_block(struct jaf_env *env, struct jaf_block *block);
|
||||
static void analyze_block(struct jaf_env *env, struct jaf_block *block);
|
||||
|
||||
static void analyze_global_declaration(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
{
|
||||
if (!decl->init)
|
||||
return;
|
||||
analyze_expression(env, &decl->init);
|
||||
assert(decl->type);
|
||||
jaf_check_type(decl->init, decl->type);
|
||||
// add initval to ain object
|
||||
struct ain_initval init = { .global_index = decl->var_no };
|
||||
jaf_to_initval(&init, decl->init);
|
||||
ain_add_initval(env->ain, &init);
|
||||
}
|
||||
|
||||
static void analyze_local_declaration(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
{
|
||||
assert(env->func_no >= 0 && env->func_no < env->ain->nr_functions);
|
||||
assert(decl->var_no >= 0 && decl->var_no < env->ain->functions[env->func_no].nr_vars);
|
||||
// add local to environment
|
||||
env->locals = xrealloc_array(env->locals, env->nr_locals, env->nr_locals+1, sizeof(struct ain_variable*));
|
||||
env->locals[env->nr_locals++] = &env->ain->functions[env->func_no].vars[decl->var_no];
|
||||
}
|
||||
|
||||
static void analyze_function(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
{
|
||||
// create new scope with function arguments
|
||||
assert(decl->func_no < env->ain->nr_functions);
|
||||
struct ain_function *fun = &env->ain->functions[decl->func_no];
|
||||
struct jaf_env *funenv = xcalloc(1, sizeof(struct jaf_env));
|
||||
funenv->ain = env->ain;
|
||||
funenv->parent = env;
|
||||
funenv->func_no = decl->func_no;
|
||||
funenv->fundecl = decl;
|
||||
funenv->nr_locals = fun->nr_args;
|
||||
funenv->locals = xcalloc(funenv->nr_locals, sizeof(struct ain_variable*));
|
||||
for (size_t i = 0; i < funenv->nr_locals; i++) {
|
||||
funenv->locals[i] = &fun->vars[i];
|
||||
}
|
||||
|
||||
_analyze_block(funenv, decl->body);
|
||||
free(funenv->locals);
|
||||
free(funenv);
|
||||
}
|
||||
|
||||
static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
if (env->parent)
|
||||
analyze_local_declaration(env, &item->decl);
|
||||
else
|
||||
analyze_global_declaration(env, &item->decl);
|
||||
switch (decl->type->type) {
|
||||
case JAF_VOID:
|
||||
ERROR("void variable declaration");
|
||||
case JAF_INT:
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
write_instruction1(out, PUSH, decl->var_no);
|
||||
if (decl->init) {
|
||||
compile_expression(ain, out, decl->init);
|
||||
} else {
|
||||
write_instruction1(out, PUSH, 0);
|
||||
}
|
||||
write_instruction0(out, ASSIGN);
|
||||
break;
|
||||
case JAF_FUNDECL:
|
||||
analyze_function(env, &item->decl);
|
||||
case JAF_FLOAT:
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
write_instruction1(out, PUSH, decl->var_no);
|
||||
if (decl->init) {
|
||||
compile_expression(ain, out, decl->init);
|
||||
} else {
|
||||
write_instruction1(out, F_PUSH, 0);
|
||||
}
|
||||
break;
|
||||
case JAF_STMT_LABELED:
|
||||
analyze_statement(env, item->label.stmt);
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
analyze_block(env, item->block);
|
||||
break;
|
||||
case JAF_STMT_EXPRESSION:
|
||||
analyze_expression(env, &item->expr);
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
analyze_expression(env, &item->cond.test);
|
||||
analyze_statement(env, item->cond.consequent);
|
||||
analyze_statement(env, item->cond.alternative);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
analyze_expression(env, &item->swi.expr);
|
||||
analyze_block(env, item->swi.body);
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
case JAF_STMT_DO_WHILE:
|
||||
analyze_expression(env, &item->while_loop.test);
|
||||
analyze_statement(env, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
analyze_block(env, item->for_loop.init);
|
||||
analyze_expression(env, &item->for_loop.test);
|
||||
analyze_expression(env, &item->for_loop.after);
|
||||
analyze_statement(env, item->for_loop.body);
|
||||
break;
|
||||
case JAF_STMT_RETURN:
|
||||
analyze_expression(env, &item->expr);
|
||||
jaf_check_type(item->expr, env->fundecl->type);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
case JAF_STMT_DEFAULT:
|
||||
analyze_statement(env, item->swi_case.stmt);
|
||||
break;
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_STRING:
|
||||
ERROR("strings not supported");
|
||||
case JAF_STRUCT:
|
||||
ERROR("structs not supported");
|
||||
case JAF_ENUM:
|
||||
ERROR("enums not supported");
|
||||
case JAF_TYPEDEF:
|
||||
ERROR("Unresolved typedef");
|
||||
case JAF_FUNCTION:
|
||||
ERROR("Function types not supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _analyze_block(struct jaf_env *env, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
analyze_statement(env, block->items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void analyze_block(struct jaf_env *env, struct jaf_block *block)
|
||||
{
|
||||
struct jaf_env *blockenv = xcalloc(1, sizeof(struct jaf_env));
|
||||
blockenv->ain = env->ain;
|
||||
blockenv->parent = env;
|
||||
|
||||
_analyze_block(blockenv, block);
|
||||
free(blockenv->locals);
|
||||
free(blockenv);
|
||||
}
|
||||
|
||||
static void resolve_types(struct ain *ain, struct jaf_block *block);
|
||||
|
||||
static void resolve_decl_types(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
if (decl->type->type == JAF_TYPEDEF)
|
||||
resolve_typedef(ain, decl->type);
|
||||
if (decl->type->type != JAF_STRUCT || !decl->type->def)
|
||||
return;
|
||||
|
||||
assert(decl->type->struct_no >= 0); // set in parse phase
|
||||
assert(decl->type->struct_no < ain->nr_structures);
|
||||
|
||||
// create struct definition in ain object
|
||||
struct jaf_block *def = decl->type->def;
|
||||
struct ain_variable *members = xcalloc(def->nr_items, sizeof(struct ain_variable));
|
||||
for (size_t i = 0; i < def->nr_items; i++) {
|
||||
members[i].name = encode_text_to_input_format(def->items[i]->decl.name->text);
|
||||
if (ain->version >= 12)
|
||||
members[i].name2 = strdup("");
|
||||
jaf_to_ain_type(ain, &members[i].type, def->items[i]->decl.type);
|
||||
}
|
||||
|
||||
struct ain_struct *s = &ain->structures[decl->type->struct_no];
|
||||
s->nr_members = def->nr_items;
|
||||
s->members = members;
|
||||
}
|
||||
|
||||
static void resolve_statement_types(struct ain *ain, struct jaf_block_item *item)
|
||||
static void compile_statement(struct ain *ain, struct buffer *out, struct jaf_block_item *item)
|
||||
{
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
resolve_decl_types(ain, &item->decl);
|
||||
compile_vardecl(ain, out, &item->decl);
|
||||
break;
|
||||
case JAF_FUNDECL:
|
||||
if (item->decl.params)
|
||||
resolve_types(ain, item->decl.params);
|
||||
resolve_types(ain, item->decl.body);
|
||||
break;
|
||||
case JAF_STMT_LABELED:
|
||||
resolve_statement_types(ain, item->label.stmt);
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
resolve_types(ain, item->block);
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
resolve_statement_types(ain, item->cond.consequent);
|
||||
resolve_statement_types(ain, item->cond.alternative);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
resolve_types(ain, item->swi.body);
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
case JAF_STMT_DO_WHILE:
|
||||
resolve_statement_types(ain, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
resolve_types(ain, item->for_loop.init);
|
||||
resolve_statement_types(ain, item->for_loop.body);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
case JAF_STMT_DEFAULT:
|
||||
resolve_statement_types(ain, item->swi_case.stmt);
|
||||
break;
|
||||
case JAF_STMT_EXPRESSION:
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_STMT_RETURN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_types(struct ain *ain, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
resolve_statement_types(ain, block->items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_variable(struct ain *ain, struct ain_variable *var, struct string *name, struct jaf_type_specifier *type)
|
||||
{
|
||||
var->name = encode_text_to_input_format(name->text);
|
||||
if (ain->version >= 12)
|
||||
var->name2 = strdup("");
|
||||
jaf_to_ain_type(ain, &var->type, type);
|
||||
}
|
||||
|
||||
static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *block, struct ain_variable *vars, int *nr_vars);
|
||||
|
||||
static struct ain_variable *block_item_get_vars(struct ain *ain, struct jaf_block_item *item, struct ain_variable *vars, int *nr_vars)
|
||||
{
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
if (!item->decl.name)
|
||||
break;
|
||||
vars = xrealloc_array(vars, *nr_vars, *nr_vars + 1, sizeof(struct ain_variable));
|
||||
init_variable(ain, vars + *nr_vars, item->decl.name, item->decl.type);
|
||||
(*nr_vars)++;
|
||||
break;
|
||||
case JAF_STMT_LABELED:
|
||||
vars = block_item_get_vars(ain, item->label.stmt, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
vars = block_get_vars(ain, item->block, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
vars = block_item_get_vars(ain, item->cond.consequent, vars, nr_vars);
|
||||
vars = block_item_get_vars(ain, item->cond.alternative, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
vars = block_get_vars(ain, item->swi.body, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
case JAF_STMT_DO_WHILE:
|
||||
vars = block_item_get_vars(ain, item->while_loop.body, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
vars = block_get_vars(ain, item->for_loop.init, vars, nr_vars);
|
||||
vars = block_item_get_vars(ain, item->for_loop.body, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
case JAF_STMT_DEFAULT:
|
||||
vars = block_item_get_vars(ain, item->swi_case.stmt, vars, nr_vars);
|
||||
break;
|
||||
|
||||
case JAF_STMT_EXPRESSION:
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_STMT_RETURN:
|
||||
break;
|
||||
|
||||
case JAF_FUNDECL:
|
||||
ERROR("Nested functions not supported");
|
||||
case JAF_STMT_LABELED:
|
||||
ERROR("Labels not supported");
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
compile_block(ain, out, item->block);
|
||||
break;
|
||||
case JAF_STMT_EXPRESSION:
|
||||
compile_expression(ain, out, item->expr);
|
||||
switch (item->expr->value_type.type) {
|
||||
case JAF_VOID:
|
||||
break;
|
||||
case JAF_INT:
|
||||
case JAF_FLOAT:
|
||||
case JAF_STRING:
|
||||
case JAF_STRUCT: // FIXME: this also needs a DELETE I think...
|
||||
case JAF_ENUM:
|
||||
case JAF_FUNCTION:
|
||||
write_instruction0(out, POP);
|
||||
break;
|
||||
// TODO: immediate ref types will need additional POP
|
||||
case JAF_TYPEDEF:
|
||||
ERROR("Unresolved typedef");
|
||||
}
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
ERROR("if not supported");
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
ERROR("switch not supported");
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
ERROR("while loops not supported");
|
||||
break;
|
||||
case JAF_STMT_DO_WHILE:
|
||||
ERROR("do-while loops not supported");
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
ERROR("for loops not supported");
|
||||
break;
|
||||
case JAF_STMT_GOTO:
|
||||
ERROR("goto not supported");
|
||||
case JAF_STMT_CONTINUE:
|
||||
break;
|
||||
case JAF_STMT_BREAK:
|
||||
ERROR("break not supported");
|
||||
break;
|
||||
case JAF_STMT_RETURN:
|
||||
if (item->expr)
|
||||
compile_expression(ain, out, item->expr);
|
||||
write_instruction0(out, RETURN);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
ERROR("switch not supported");
|
||||
break;
|
||||
case JAF_STMT_DEFAULT:
|
||||
ERROR("switch not supported");
|
||||
break;
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *block, struct ain_variable *vars, int *nr_vars)
|
||||
static void compile_block(struct ain *ain, struct buffer *out, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
vars = block_item_get_vars(ain, block->items[i], vars, nr_vars);
|
||||
compile_statement(ain, out, block->items[i]);
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
static void function_init_vars(struct ain *ain, struct ain_function *f, struct jaf_declaration *decl)
|
||||
static void compile_function(struct ain *ain, struct buffer *out, struct jaf_declaration *decl)
|
||||
{
|
||||
f->nr_args = decl->params ? decl->params->nr_items : 0;
|
||||
f->nr_vars = f->nr_args;
|
||||
f->vars = xcalloc(f->nr_args, sizeof(struct ain_variable));
|
||||
for (int i = 0; i < f->nr_args; i++) {
|
||||
assert(decl->params->items[i]->kind == JAF_DECLARATION);
|
||||
assert(decl->params->items[i]->decl.name);
|
||||
struct jaf_declaration *param = &decl->params->items[i]->decl;
|
||||
init_variable(ain, &f->vars[i], param->name, param->type);
|
||||
}
|
||||
f->vars = block_get_vars(ain, decl->body, f->vars, &f->nr_vars);
|
||||
assert(decl->func_no >= 0 && decl->func_no < ain->nr_functions);
|
||||
ain->functions[decl->func_no].address = out->index;
|
||||
write_instruction1(out, FUNC, decl->func_no);
|
||||
compile_block(ain, out, decl->body);
|
||||
write_instruction1(out, ENDFUNC, decl->func_no);
|
||||
}
|
||||
|
||||
static void add_function(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
struct ain_function f = {0};
|
||||
f.name = strdup(decl->name->text);
|
||||
jaf_to_ain_type(ain, &f.return_type, decl->type);
|
||||
function_init_vars(ain, &f, decl);
|
||||
|
||||
decl->func_no = ain_add_function(ain, &f);
|
||||
}
|
||||
|
||||
static void add_global(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
char *u = encode_text_to_input_format(decl->name->text);
|
||||
struct ain_variable *v = ain_add_global(ain, u);
|
||||
jaf_to_ain_type(ain, &v->type, decl->type);
|
||||
decl->var_no = v - ain->globals;
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void compile_declaration(possibly_unused struct ain *ain, struct jaf_block_item *decl)
|
||||
static void compile_declaration(struct ain *ain, struct buffer *code, struct jaf_block_item *decl)
|
||||
{
|
||||
if (decl->kind == JAF_FUNDECL) {
|
||||
WARNING("Functions not supported");
|
||||
compile_function(ain, code, &decl->decl);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: global constructors/array allocations
|
||||
}
|
||||
|
||||
static struct ain_variable *jaf_scope_loopup(struct jaf_env *env, char *name)
|
||||
{
|
||||
for (size_t i = 0; i < env->nr_locals; i++) {
|
||||
if (!strcmp(env->locals[i]->name, name))
|
||||
return env->locals[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ain_variable *jaf_env_lookup(struct jaf_env *env, struct string *name)
|
||||
{
|
||||
struct ain_variable *r;
|
||||
char *u = encode_text_to_input_format(name->text);
|
||||
struct jaf_env *scope = env;
|
||||
while (scope) {
|
||||
if ((r = jaf_scope_loopup(env, u)))
|
||||
break;
|
||||
scope = scope->parent;
|
||||
}
|
||||
if (!r) {
|
||||
r = ain_get_global(env->ain, u);
|
||||
}
|
||||
free(u);
|
||||
return r;
|
||||
}
|
||||
|
||||
void jaf_compile(struct ain *out, const char *path)
|
||||
{
|
||||
if (path) {
|
||||
@@ -492,28 +474,18 @@ void jaf_compile(struct ain *out, const char *path)
|
||||
if (!jaf_toplevel)
|
||||
ERROR("Failed to parse .jaf file");
|
||||
|
||||
struct jaf_env env = {
|
||||
.ain = out,
|
||||
.parent = NULL
|
||||
};
|
||||
jaf_toplevel = jaf_static_analyze(out, jaf_toplevel);
|
||||
|
||||
// pass 1: typedefs && struct definitions
|
||||
resolve_types(out, jaf_toplevel);
|
||||
// pass 2: register globals (names, types)
|
||||
struct buffer buf = {
|
||||
.buf = out->code,
|
||||
.size = out->code_size,
|
||||
.index = out->code_size
|
||||
};
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_items; i++) {
|
||||
if (jaf_toplevel->items[i]->decl.name) {
|
||||
if (jaf_toplevel->items[i]->kind == JAF_FUNDECL)
|
||||
add_function(out, &jaf_toplevel->items[i]->decl);
|
||||
else
|
||||
add_global(out, &jaf_toplevel->items[i]->decl);
|
||||
}
|
||||
}
|
||||
// pass 3: type analysis & simplification & global initvals (static analysis)
|
||||
_analyze_block(&env, jaf_toplevel);
|
||||
// pass 4: generate bytecode
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_items; i++) {
|
||||
compile_declaration(out, jaf_toplevel->items[i]);
|
||||
compile_declaration(out, &buf, jaf_toplevel->items[i]);
|
||||
}
|
||||
out->code = buf.buf;
|
||||
out->code_size = buf.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
|
||||
|
||||
@@ -22,102 +22,125 @@
|
||||
|
||||
struct jaf_expression *jaf_simplify(struct jaf_expression *in);
|
||||
|
||||
static struct jaf_expression *jaf_simplify_negation(struct jaf_expression *expr)
|
||||
static struct jaf_expression *jaf_simplify_negation(struct jaf_expression *in)
|
||||
{
|
||||
struct jaf_expression *expr = in->expr;
|
||||
if (expr->type == JAF_EXP_INT) {
|
||||
free(in);
|
||||
expr->i = -expr->i;
|
||||
return expr;
|
||||
}
|
||||
if (expr->type == JAF_EXP_FLOAT) {
|
||||
free(in);
|
||||
expr->f = -expr->f;
|
||||
return expr;
|
||||
}
|
||||
|
||||
return jaf_unary_expr(JAF_UNARY_MINUS, expr);
|
||||
return in;
|
||||
}
|
||||
|
||||
static struct jaf_expression *jaf_simplify_bitnot(struct jaf_expression *expr)
|
||||
static struct jaf_expression *jaf_simplify_bitnot(struct jaf_expression *in)
|
||||
{
|
||||
struct jaf_expression *expr = in->expr;
|
||||
if (expr->type == JAF_EXP_INT) {
|
||||
free(in);
|
||||
expr->i = ~expr->i;
|
||||
return expr;
|
||||
}
|
||||
|
||||
return jaf_unary_expr(JAF_BIT_NOT, expr);
|
||||
return in;
|
||||
}
|
||||
|
||||
static struct jaf_expression *jaf_simplify_lognot(struct jaf_expression *expr)
|
||||
static struct jaf_expression *jaf_simplify_lognot(struct jaf_expression *in)
|
||||
{
|
||||
struct jaf_expression *expr = in->expr;
|
||||
if (expr->type == JAF_EXP_INT) {
|
||||
free(in);
|
||||
expr->i = !expr->i;
|
||||
return expr;
|
||||
}
|
||||
|
||||
return jaf_unary_expr(JAF_LOG_NOT, expr);
|
||||
return in;
|
||||
}
|
||||
|
||||
static struct jaf_expression *jaf_simplify_unary(struct jaf_expression *in)
|
||||
{
|
||||
struct jaf_expression *out = jaf_simplify(in->expr);
|
||||
struct jaf_expression *r = in->expr = jaf_simplify(in->expr);
|
||||
switch (in->op) {
|
||||
case JAF_UNARY_PLUS:
|
||||
return out;
|
||||
free(in);
|
||||
return r;
|
||||
case JAF_UNARY_MINUS:
|
||||
return jaf_simplify_negation(out);
|
||||
return jaf_simplify_negation(in);
|
||||
case JAF_BIT_NOT:
|
||||
return jaf_simplify_bitnot(out);
|
||||
return jaf_simplify_bitnot(in);
|
||||
case JAF_LOG_NOT:
|
||||
return jaf_simplify_lognot(out);
|
||||
return jaf_simplify_lognot(in);
|
||||
case JAF_AMPERSAND:
|
||||
case JAF_PRE_INC:
|
||||
case JAF_PRE_DEC:
|
||||
case JAF_POST_INC:
|
||||
case JAF_POST_DEC:
|
||||
return jaf_unary_expr(in->op, out);
|
||||
return in;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ERROR("Invalid unary operator");
|
||||
}
|
||||
|
||||
static void jaf_normalize_for_arithmetic(struct jaf_expression *lhs, struct jaf_expression *rhs)
|
||||
static struct jaf_expression *simplify_cast_to_float(struct jaf_expression *e)
|
||||
{
|
||||
if (lhs->type == JAF_EXP_FLOAT && rhs->type == JAF_EXP_INT) {
|
||||
rhs->type = JAF_EXP_FLOAT;
|
||||
rhs->f = rhs->i;
|
||||
} else if (lhs->type == JAF_EXP_INT && rhs->type == JAF_EXP_FLOAT) {
|
||||
lhs->type = JAF_EXP_FLOAT;
|
||||
lhs->f = lhs->i;
|
||||
if (e->value_type.type == JAF_FLOAT)
|
||||
return e;
|
||||
if (e->type == JAF_EXP_INT) {
|
||||
float f = e->i;
|
||||
e->type = JAF_EXP_FLOAT;
|
||||
e->f = f;
|
||||
return e;
|
||||
}
|
||||
return jaf_cast_expression(JAF_FLOAT, e);
|
||||
}
|
||||
|
||||
static void jaf_normalize_for_arithmetic(struct jaf_expression *e)
|
||||
{
|
||||
if (e->lhs->value_type.type == JAF_FLOAT || e->rhs->value_type.type == JAF_FLOAT) {
|
||||
e->lhs = simplify_cast_to_float(e->lhs);
|
||||
e->rhs = simplify_cast_to_float(e->rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#define SIMPLIFY_ARITHMETIC_FUN(name, op_name, op) \
|
||||
static struct jaf_expression *name(struct jaf_expression *lhs, struct jaf_expression *rhs) \
|
||||
static struct jaf_expression *name(struct jaf_expression *e) \
|
||||
{ \
|
||||
jaf_normalize_for_arithmetic(lhs, rhs); \
|
||||
if (lhs->type == JAF_EXP_INT && rhs->type == JAF_EXP_INT) { \
|
||||
lhs->i = lhs->i op rhs->i; \
|
||||
free(rhs); \
|
||||
return lhs; \
|
||||
jaf_normalize_for_arithmetic(e); \
|
||||
if (e->lhs->type == JAF_EXP_INT && e->rhs->type == JAF_EXP_INT) { \
|
||||
struct jaf_expression *r = e->lhs; \
|
||||
r->i = r->i op e->rhs->i; \
|
||||
free(e->rhs); \
|
||||
free(e); \
|
||||
return r; \
|
||||
} \
|
||||
if (lhs->type == JAF_EXP_FLOAT && rhs->type == JAF_EXP_FLOAT) { \
|
||||
lhs->f = lhs->f op rhs->f; \
|
||||
free(rhs); \
|
||||
return lhs; \
|
||||
if (e->lhs->type == JAF_EXP_FLOAT && e->rhs->type == JAF_EXP_FLOAT) { \
|
||||
struct jaf_expression *r = e->lhs; \
|
||||
r->f = r->f op e->rhs->f; \
|
||||
free(e->rhs); \
|
||||
free(e); \
|
||||
return r; \
|
||||
} \
|
||||
return jaf_binary_expr(op_name, lhs, rhs); \
|
||||
return e; \
|
||||
}
|
||||
|
||||
#define SIMPLIFY_INTEGER_FUN(name, op_name, op) \
|
||||
static struct jaf_expression *name(struct jaf_expression *lhs, struct jaf_expression *rhs) \
|
||||
static struct jaf_expression *name(struct jaf_expression *e) \
|
||||
{ \
|
||||
jaf_normalize_for_arithmetic(lhs, rhs); \
|
||||
if (lhs->type == JAF_EXP_INT && rhs->type == JAF_EXP_INT) { \
|
||||
lhs->i = lhs->i op rhs->i; \
|
||||
free(rhs); \
|
||||
return lhs; \
|
||||
if (e->lhs->type == JAF_EXP_INT && e->rhs->type == JAF_EXP_INT) { \
|
||||
struct jaf_expression *r = e->lhs; \
|
||||
r->i = r->i op e->rhs->i; \
|
||||
free(e->rhs); \
|
||||
free(e); \
|
||||
return r; \
|
||||
} \
|
||||
return jaf_binary_expr(op_name, lhs, rhs); \
|
||||
return e; \
|
||||
}
|
||||
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_multiply, JAF_MULTIPLY, *)
|
||||
@@ -138,48 +161,47 @@ SIMPLIFY_INTEGER_FUN (jaf_simplify_bitior, JAF_BIT_IOR, |)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_logand, JAF_LOG_AND, &&)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_logor, JAF_LOG_OR, ||)
|
||||
|
||||
static struct jaf_expression *jaf_simplify_binary(struct jaf_expression *in)
|
||||
static struct jaf_expression *jaf_simplify_binary(struct jaf_expression *e)
|
||||
{
|
||||
enum jaf_operator op = in->op;
|
||||
struct jaf_expression *lhs = jaf_simplify(in->lhs);
|
||||
struct jaf_expression *rhs = jaf_simplify(in->rhs);
|
||||
free(in);
|
||||
enum jaf_operator op = e->op;
|
||||
e->lhs = jaf_simplify(e->lhs);
|
||||
e->rhs = jaf_simplify(e->rhs);
|
||||
|
||||
switch (op) {
|
||||
case JAF_MULTIPLY:
|
||||
return jaf_simplify_multiply(lhs, rhs);
|
||||
return jaf_simplify_multiply(e);
|
||||
case JAF_DIVIDE:
|
||||
return jaf_simplify_divide(lhs, rhs);
|
||||
return jaf_simplify_divide(e);
|
||||
case JAF_REMAINDER:
|
||||
return jaf_simplify_remainder(lhs, rhs);
|
||||
return jaf_simplify_remainder(e);
|
||||
case JAF_PLUS:
|
||||
return jaf_simplify_plus(lhs, rhs);
|
||||
return jaf_simplify_plus(e);
|
||||
case JAF_MINUS:
|
||||
return jaf_simplify_minus(lhs, rhs);
|
||||
return jaf_simplify_minus(e);
|
||||
case JAF_LSHIFT:
|
||||
return jaf_simplify_lshift(lhs, rhs);
|
||||
return jaf_simplify_lshift(e);
|
||||
case JAF_RSHIFT:
|
||||
return jaf_simplify_rshift(lhs, rhs);
|
||||
return jaf_simplify_rshift(e);
|
||||
case JAF_LT:
|
||||
return jaf_simplify_lt(lhs, rhs);
|
||||
return jaf_simplify_lt(e);
|
||||
case JAF_GT:
|
||||
return jaf_simplify_gt(lhs, rhs);
|
||||
return jaf_simplify_gt(e);
|
||||
case JAF_LTE:
|
||||
return jaf_simplify_lte(lhs, rhs);
|
||||
return jaf_simplify_lte(e);
|
||||
case JAF_GTE:
|
||||
return jaf_simplify_gte(lhs, rhs);
|
||||
return jaf_simplify_gte(e);
|
||||
case JAF_EQ:
|
||||
return jaf_simplify_eq(lhs, rhs);
|
||||
return jaf_simplify_eq(e);
|
||||
case JAF_BIT_AND:
|
||||
return jaf_simplify_bitand(lhs, rhs);
|
||||
return jaf_simplify_bitand(e);
|
||||
case JAF_BIT_XOR:
|
||||
return jaf_simplify_bitxor(lhs, rhs);
|
||||
return jaf_simplify_bitxor(e);
|
||||
case JAF_BIT_IOR:
|
||||
return jaf_simplify_bitior(lhs, rhs);
|
||||
return jaf_simplify_bitior(e);
|
||||
case JAF_LOG_AND:
|
||||
return jaf_simplify_logand(lhs, rhs);
|
||||
return jaf_simplify_logand(e);
|
||||
case JAF_LOG_OR:
|
||||
return jaf_simplify_logor(lhs, rhs);
|
||||
return jaf_simplify_logor(e);
|
||||
case JAF_ASSIGN:
|
||||
case JAF_MUL_ASSIGN:
|
||||
case JAF_DIV_ASSIGN:
|
||||
@@ -192,7 +214,7 @@ static struct jaf_expression *jaf_simplify_binary(struct jaf_expression *in)
|
||||
case JAF_XOR_ASSIGN:
|
||||
case JAF_OR_ASSIGN:
|
||||
case JAF_REF_ASSIGN:
|
||||
return jaf_binary_expr(op, lhs, rhs);
|
||||
return e;
|
||||
default:
|
||||
ERROR("Invalid binary operator");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,451 @@
|
||||
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "system4/string.h"
|
||||
#include "ainedit.h"
|
||||
#include "jaf.h"
|
||||
|
||||
static void define_types(struct ain *ain, struct jaf_block_item *decl);
|
||||
static void jaf_resolve_types(struct ain *ain, struct jaf_block *block);
|
||||
static void jaf_process_declarations(struct ain *ain, struct jaf_block *block);
|
||||
static void jaf_analyze_block(struct jaf_env *env, struct jaf_block *block);
|
||||
|
||||
void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type)
|
||||
{
|
||||
if (!type->name)
|
||||
ERROR("Anonymous structs not supported");
|
||||
|
||||
char *u = encode_text_to_input_format(type->name->text);
|
||||
if (ain_get_struct(ain, u)) {
|
||||
ERROR("Redefining structs not supported");
|
||||
}
|
||||
|
||||
type->struct_no = ain_add_struct(ain, u);
|
||||
free(u);
|
||||
|
||||
for (size_t i = 0; i < type->def->nr_items; i++) {
|
||||
define_types(ain, type->def->items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void define_types(struct ain *ain, struct jaf_block_item *decl)
|
||||
{
|
||||
if (!decl)
|
||||
ERROR("DECL IS NULL");
|
||||
if (!decl->decl.type)
|
||||
ERROR("TYPE IS NULL");
|
||||
if (decl->decl.type->type != JAF_STRUCT)
|
||||
return;
|
||||
|
||||
jaf_define_struct(ain, decl->decl.type);
|
||||
}
|
||||
|
||||
static enum ain_data_type jaf_to_ain_data_type(enum jaf_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case JAF_VOID: return AIN_VOID;
|
||||
case JAF_INT: return AIN_INT;
|
||||
case JAF_FLOAT: return AIN_FLOAT;
|
||||
case JAF_STRING: return AIN_STRING;
|
||||
case JAF_STRUCT: return AIN_STRUCT;
|
||||
case JAF_ENUM: ERROR("Enums not supported");
|
||||
default: ERROR("Unknown type: %d", type);
|
||||
}
|
||||
}
|
||||
|
||||
static void jaf_to_ain_type(possibly_unused struct ain *ain, struct ain_type *out, struct jaf_type_specifier *in)
|
||||
{
|
||||
out->data = jaf_to_ain_data_type(in->type);
|
||||
if (in->type == JAF_STRUCT) {
|
||||
out->struc = in->struct_no;
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_typedef(struct ain *ain, struct jaf_type_specifier *type)
|
||||
{
|
||||
char *u = encode_text_to_input_format(type->name->text);
|
||||
int sno = ain_get_struct_no(ain, u);
|
||||
if (sno) {
|
||||
type->type = JAF_STRUCT;
|
||||
type->struct_no = sno;
|
||||
} else {
|
||||
ERROR("Failed to resolve typedef \"%s\"", type->name->text);
|
||||
}
|
||||
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void jaf_to_initval(struct ain_initval *dst, struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->type) {
|
||||
case JAF_EXP_INT:
|
||||
dst->data_type = AIN_INT;
|
||||
dst->int_value = expr->i;
|
||||
break;
|
||||
case JAF_EXP_FLOAT:
|
||||
dst->data_type = AIN_FLOAT;
|
||||
dst->float_value = expr->f;
|
||||
break;
|
||||
case JAF_EXP_STRING:
|
||||
dst->data_type = AIN_STRING;
|
||||
dst->string_value = strdup(expr->s->text);
|
||||
break;
|
||||
default:
|
||||
ERROR("Initval is not constant");
|
||||
}
|
||||
}
|
||||
|
||||
static void analyze_expression(struct jaf_env *env, struct jaf_expression **expr)
|
||||
{
|
||||
if (!*expr)
|
||||
return;
|
||||
jaf_derive_types(env, *expr);
|
||||
*expr = jaf_simplify(*expr);
|
||||
}
|
||||
|
||||
static void analyze_block(struct jaf_env *env, struct jaf_block *block);
|
||||
|
||||
static void analyze_global_declaration(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
{
|
||||
if (!decl->init)
|
||||
return;
|
||||
analyze_expression(env, &decl->init);
|
||||
assert(decl->type);
|
||||
jaf_check_type(decl->init, decl->type);
|
||||
// add initval to ain object
|
||||
struct ain_initval init = { .global_index = decl->var_no };
|
||||
jaf_to_initval(&init, decl->init);
|
||||
ain_add_initval(env->ain, &init);
|
||||
}
|
||||
|
||||
static void analyze_local_declaration(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
{
|
||||
assert(env->func_no >= 0 && env->func_no < env->ain->nr_functions);
|
||||
assert(decl->var_no >= 0 && decl->var_no < env->ain->functions[env->func_no].nr_vars);
|
||||
// add local to environment
|
||||
env->locals = xrealloc_array(env->locals, env->nr_locals, env->nr_locals+1, sizeof(struct ain_variable*));
|
||||
env->locals[env->nr_locals++] = &env->ain->functions[env->func_no].vars[decl->var_no];
|
||||
}
|
||||
|
||||
static void analyze_function(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
{
|
||||
// create new scope with function arguments
|
||||
assert(decl->func_no < env->ain->nr_functions);
|
||||
struct ain_function *fun = &env->ain->functions[decl->func_no];
|
||||
struct jaf_env *funenv = xcalloc(1, sizeof(struct jaf_env));
|
||||
funenv->ain = env->ain;
|
||||
funenv->parent = env;
|
||||
funenv->func_no = decl->func_no;
|
||||
funenv->fundecl = decl;
|
||||
funenv->nr_locals = fun->nr_args;
|
||||
funenv->locals = xcalloc(funenv->nr_locals, sizeof(struct ain_variable*));
|
||||
for (size_t i = 0; i < funenv->nr_locals; i++) {
|
||||
funenv->locals[i] = &fun->vars[i];
|
||||
}
|
||||
|
||||
jaf_analyze_block(funenv, decl->body);
|
||||
free(funenv->locals);
|
||||
free(funenv);
|
||||
}
|
||||
|
||||
static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
if (env->parent)
|
||||
analyze_local_declaration(env, &item->decl);
|
||||
else
|
||||
analyze_global_declaration(env, &item->decl);
|
||||
break;
|
||||
case JAF_FUNDECL:
|
||||
analyze_function(env, &item->decl);
|
||||
break;
|
||||
case JAF_STMT_LABELED:
|
||||
analyze_statement(env, item->label.stmt);
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
analyze_block(env, item->block);
|
||||
break;
|
||||
case JAF_STMT_EXPRESSION:
|
||||
analyze_expression(env, &item->expr);
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
analyze_expression(env, &item->cond.test);
|
||||
analyze_statement(env, item->cond.consequent);
|
||||
analyze_statement(env, item->cond.alternative);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
analyze_expression(env, &item->swi.expr);
|
||||
analyze_block(env, item->swi.body);
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
case JAF_STMT_DO_WHILE:
|
||||
analyze_expression(env, &item->while_loop.test);
|
||||
analyze_statement(env, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
analyze_block(env, item->for_loop.init);
|
||||
analyze_expression(env, &item->for_loop.test);
|
||||
analyze_expression(env, &item->for_loop.after);
|
||||
analyze_statement(env, item->for_loop.body);
|
||||
break;
|
||||
case JAF_STMT_RETURN:
|
||||
analyze_expression(env, &item->expr);
|
||||
jaf_check_type(item->expr, env->fundecl->type);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
case JAF_STMT_DEFAULT:
|
||||
analyze_statement(env, item->swi_case.stmt);
|
||||
break;
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void jaf_analyze_block(struct jaf_env *env, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
analyze_statement(env, block->items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void analyze_block(struct jaf_env *env, struct jaf_block *block)
|
||||
{
|
||||
struct jaf_env *blockenv = xcalloc(1, sizeof(struct jaf_env));
|
||||
blockenv->ain = env->ain;
|
||||
blockenv->parent = env;
|
||||
blockenv->func_no = env->func_no;
|
||||
blockenv->fundecl = env->fundecl;
|
||||
|
||||
jaf_analyze_block(blockenv, block);
|
||||
free(blockenv->locals);
|
||||
free(blockenv);
|
||||
}
|
||||
|
||||
static void resolve_decl_types(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
if (decl->type->type == JAF_TYPEDEF)
|
||||
resolve_typedef(ain, decl->type);
|
||||
if (decl->type->type != JAF_STRUCT || !decl->type->def)
|
||||
return;
|
||||
|
||||
assert(decl->type->struct_no >= 0); // set in parse phase
|
||||
assert(decl->type->struct_no < ain->nr_structures);
|
||||
|
||||
// create struct definition in ain object
|
||||
struct jaf_block *def = decl->type->def;
|
||||
struct ain_variable *members = xcalloc(def->nr_items, sizeof(struct ain_variable));
|
||||
for (size_t i = 0; i < def->nr_items; i++) {
|
||||
members[i].name = encode_text_to_input_format(def->items[i]->decl.name->text);
|
||||
if (ain->version >= 12)
|
||||
members[i].name2 = strdup("");
|
||||
jaf_to_ain_type(ain, &members[i].type, def->items[i]->decl.type);
|
||||
}
|
||||
|
||||
struct ain_struct *s = &ain->structures[decl->type->struct_no];
|
||||
s->nr_members = def->nr_items;
|
||||
s->members = members;
|
||||
}
|
||||
|
||||
static void resolve_statement_types(struct ain *ain, struct jaf_block_item *item)
|
||||
{
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
resolve_decl_types(ain, &item->decl);
|
||||
break;
|
||||
case JAF_FUNDECL:
|
||||
if (item->decl.params)
|
||||
jaf_resolve_types(ain, item->decl.params);
|
||||
jaf_resolve_types(ain, item->decl.body);
|
||||
break;
|
||||
case JAF_STMT_LABELED:
|
||||
resolve_statement_types(ain, item->label.stmt);
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
jaf_resolve_types(ain, item->block);
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
resolve_statement_types(ain, item->cond.consequent);
|
||||
resolve_statement_types(ain, item->cond.alternative);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
jaf_resolve_types(ain, item->swi.body);
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
case JAF_STMT_DO_WHILE:
|
||||
resolve_statement_types(ain, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
jaf_resolve_types(ain, item->for_loop.init);
|
||||
resolve_statement_types(ain, item->for_loop.body);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
case JAF_STMT_DEFAULT:
|
||||
resolve_statement_types(ain, item->swi_case.stmt);
|
||||
break;
|
||||
case JAF_STMT_EXPRESSION:
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_STMT_RETURN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void jaf_resolve_types(struct ain *ain, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
resolve_statement_types(ain, block->items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_variable(struct ain *ain, struct ain_variable *var, struct string *name, struct jaf_type_specifier *type)
|
||||
{
|
||||
var->name = encode_text_to_input_format(name->text);
|
||||
if (ain->version >= 12)
|
||||
var->name2 = strdup("");
|
||||
jaf_to_ain_type(ain, &var->type, type);
|
||||
}
|
||||
|
||||
static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *block, struct ain_variable *vars, int *nr_vars);
|
||||
|
||||
static struct ain_variable *block_item_get_vars(struct ain *ain, struct jaf_block_item *item, struct ain_variable *vars, int *nr_vars)
|
||||
{
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
if (!item->decl.name)
|
||||
break;
|
||||
vars = xrealloc_array(vars, *nr_vars, *nr_vars + 1, sizeof(struct ain_variable));
|
||||
init_variable(ain, vars + *nr_vars, item->decl.name, item->decl.type);
|
||||
(*nr_vars)++;
|
||||
break;
|
||||
case JAF_STMT_LABELED:
|
||||
vars = block_item_get_vars(ain, item->label.stmt, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
vars = block_get_vars(ain, item->block, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
vars = block_item_get_vars(ain, item->cond.consequent, vars, nr_vars);
|
||||
vars = block_item_get_vars(ain, item->cond.alternative, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
vars = block_get_vars(ain, item->swi.body, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
case JAF_STMT_DO_WHILE:
|
||||
vars = block_item_get_vars(ain, item->while_loop.body, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
vars = block_get_vars(ain, item->for_loop.init, vars, nr_vars);
|
||||
vars = block_item_get_vars(ain, item->for_loop.body, vars, nr_vars);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
case JAF_STMT_DEFAULT:
|
||||
vars = block_item_get_vars(ain, item->swi_case.stmt, vars, nr_vars);
|
||||
break;
|
||||
|
||||
case JAF_STMT_EXPRESSION:
|
||||
case JAF_STMT_GOTO:
|
||||
case JAF_STMT_CONTINUE:
|
||||
case JAF_STMT_BREAK:
|
||||
case JAF_STMT_RETURN:
|
||||
break;
|
||||
|
||||
case JAF_FUNDECL:
|
||||
ERROR("Nested functions not supported");
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *block, struct ain_variable *vars, int *nr_vars)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
vars = block_item_get_vars(ain, block->items[i], vars, nr_vars);
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
static void function_init_vars(struct ain *ain, struct ain_function *f, struct jaf_declaration *decl)
|
||||
{
|
||||
f->nr_args = decl->params ? decl->params->nr_items : 0;
|
||||
f->nr_vars = f->nr_args;
|
||||
f->vars = xcalloc(f->nr_args, sizeof(struct ain_variable));
|
||||
for (int i = 0; i < f->nr_args; i++) {
|
||||
assert(decl->params->items[i]->kind == JAF_DECLARATION);
|
||||
assert(decl->params->items[i]->decl.name);
|
||||
struct jaf_declaration *param = &decl->params->items[i]->decl;
|
||||
init_variable(ain, &f->vars[i], param->name, param->type);
|
||||
}
|
||||
f->vars = block_get_vars(ain, decl->body, f->vars, &f->nr_vars);
|
||||
}
|
||||
|
||||
static void add_function(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
struct ain_function f = {0};
|
||||
f.name = strdup(decl->name->text);
|
||||
jaf_to_ain_type(ain, &f.return_type, decl->type);
|
||||
function_init_vars(ain, &f, decl);
|
||||
|
||||
decl->func_no = ain_add_function(ain, &f);
|
||||
}
|
||||
|
||||
static void add_global(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
char *u = encode_text_to_input_format(decl->name->text);
|
||||
struct ain_variable *v = ain_add_global(ain, u);
|
||||
jaf_to_ain_type(ain, &v->type, decl->type);
|
||||
decl->var_no = v - ain->globals;
|
||||
free(u);
|
||||
}
|
||||
|
||||
static void jaf_process_declarations(struct ain *ain, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
if (block->items[i]->decl.name) {
|
||||
if (block->items[i]->kind == JAF_FUNDECL)
|
||||
add_function(ain, &block->items[i]->decl);
|
||||
else
|
||||
add_global(ain, &block->items[i]->decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct jaf_block *jaf_static_analyze(struct ain *ain, struct jaf_block *block)
|
||||
{
|
||||
struct jaf_env env = {
|
||||
.ain = ain,
|
||||
.parent = NULL
|
||||
};
|
||||
|
||||
// pass 1: typedefs && struct definitions
|
||||
jaf_resolve_types(ain, block);
|
||||
// pass 2: register globals (names, types)
|
||||
jaf_process_declarations(ain, block);
|
||||
// pass 3: type analysis & simplification & global initvals
|
||||
jaf_analyze_block(&env, block);
|
||||
|
||||
return block;
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
#define TYPE_CHECK(expr, expected) { if (expr->value_type.type != expected) TYPE_ERROR(expr, expected); }
|
||||
#define TYPE_CHECK_NUMERIC(expr) { if (expr->derived_type != JAF_INT && expr->derived_type != JAF_FLOAT) TYPE_ERROR(expr, JAF_INT); }
|
||||
|
||||
static const char *jaf_typestr(enum jaf_type type)
|
||||
const char *jaf_typestr(enum jaf_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case JAF_VOID: return "void";
|
||||
@@ -198,11 +198,49 @@ static void ain_to_jaf_type(struct jaf_type_specifier *dst, struct ain_type *src
|
||||
}
|
||||
}
|
||||
|
||||
static struct ain_variable *jaf_scope_lookup(struct jaf_env *env, char *name, int *var_no)
|
||||
{
|
||||
for (size_t i = 0; i < env->nr_locals; i++) {
|
||||
if (!strcmp(env->locals[i]->name, name)) {
|
||||
*var_no = i;
|
||||
return env->locals[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ain_variable *jaf_env_lookup(struct jaf_env *env, struct string *name, int *var_no)
|
||||
{
|
||||
char *u = encode_text_to_input_format(name->text);
|
||||
struct jaf_env *scope = env;
|
||||
while (scope) {
|
||||
struct ain_variable *v = jaf_scope_lookup(env, u, var_no);
|
||||
if (v) {
|
||||
free(u);
|
||||
return v;
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
|
||||
int no = ain_get_global_no(env->ain, u);
|
||||
free(u);
|
||||
|
||||
if (no >= 0) {
|
||||
*var_no = no;
|
||||
return &env->ain->globals[no];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void jaf_check_types_identifier(struct jaf_env *env, struct jaf_expression *expr)
|
||||
{
|
||||
struct ain_variable *v = jaf_env_lookup(env, expr->s);
|
||||
int var_no;
|
||||
struct ain_variable *v = jaf_env_lookup(env, expr->ident.name, &var_no);
|
||||
if (v) {
|
||||
ain_to_jaf_type(&expr->value_type, &v->type);
|
||||
expr->ident.var_type = v->var_type;
|
||||
expr->ident.var_no = var_no;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ ainedit = ['../../cJSON.c',
|
||||
'jaf_ast.c',
|
||||
'jaf_compile.c',
|
||||
'jaf_eval.c',
|
||||
'jaf_static_analysis.c',
|
||||
'jaf_types.c',
|
||||
'json.c',
|
||||
'repack.c',
|
||||
|
||||
Reference in New Issue
Block a user