mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-04 04:48:09 +03:00
ainedit: initial .jaf support
Initial support for compiling .jaf (System 4 language) files. So far this is limited to adding struct definitions and declaring new globals. The actual bytecode compilation is not yet implemented. This Bison grammar is based on a C grammar and should cover 95% of the System 4 language syntax already, though many AST nodes are not yet implemented.
This commit is contained in:
@@ -168,6 +168,7 @@ struct ain_initval {
|
||||
union {
|
||||
char *string_value;
|
||||
int32_t int_value;
|
||||
float float_value;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -321,6 +322,10 @@ void ain_decrypt(uint8_t *buf, size_t len);
|
||||
struct ain_function *ain_get_function(struct ain *ain, char *name);
|
||||
int ain_get_function_index(struct ain *ain, struct ain_function *f);
|
||||
struct ain_struct *ain_get_struct(struct ain *ain, char *name);
|
||||
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);
|
||||
void ain_add_initval(struct ain *ain, struct ain_initval *init);
|
||||
|
||||
void ain_free(struct ain *ain);
|
||||
void ain_free_functions(struct ain *ain);
|
||||
|
||||
@@ -61,15 +61,20 @@ static void init_func_ht(struct ain *ain)
|
||||
}
|
||||
}
|
||||
|
||||
static void struct_ht_add(struct ain *ain, struct ain_struct *s)
|
||||
{
|
||||
struct ht_slot *kv = ht_put(ain->_struct_ht, s->name);
|
||||
if (kv->value) {
|
||||
ERROR("Duplicate structure names: '%s'", s->name);
|
||||
}
|
||||
kv->value = s;
|
||||
}
|
||||
|
||||
static void init_struct_ht(struct ain *ain)
|
||||
{
|
||||
ain->_struct_ht = ht_create(1024);
|
||||
for (int i = 0; i < ain->nr_structures; i++) {
|
||||
struct ht_slot *kv = ht_put(ain->_struct_ht, ain->structures[i].name);
|
||||
if (kv->value) {
|
||||
ERROR("Duplicate structure names: '%s'", ain->structures[i].name);
|
||||
}
|
||||
kv->value = &ain->structures[i];
|
||||
struct_ht_add(ain, &ain->structures[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +188,41 @@ struct ain_struct *ain_get_struct(struct ain *ain, char *name)
|
||||
return ht_get(ain->_struct_ht, name);
|
||||
}
|
||||
|
||||
int ain_get_struct_no(struct ain *ain, char *name)
|
||||
{
|
||||
struct ain_struct *s = ain_get_struct(ain, name);
|
||||
return s ? s - ain->structures : -1;
|
||||
}
|
||||
|
||||
int ain_add_struct(struct ain *ain, char *name)
|
||||
{
|
||||
ain->structures = xrealloc_array(ain->structures, ain->nr_structures, ain->nr_structures+1, sizeof(struct ain_struct));
|
||||
ain->structures[ain->nr_structures].name = strdup(name);
|
||||
ain->structures[ain->nr_structures].constructor = -1;
|
||||
ain->structures[ain->nr_structures].destructor = -1;
|
||||
struct_ht_add(ain, &ain->structures[ain->nr_structures]);
|
||||
ain->nr_structures++;
|
||||
return ain->nr_structures - 1;
|
||||
}
|
||||
|
||||
struct ain_variable *ain_add_global(struct ain *ain, char *name)
|
||||
{
|
||||
int no = ain->nr_globals;
|
||||
ain->globals = xrealloc_array(ain->globals, ain->nr_globals, ain->nr_globals+1, sizeof(struct ain_variable));
|
||||
ain->globals[no].name = strdup(name);
|
||||
if (ain->version >= 12)
|
||||
ain->globals[no].name2 = strdup("");
|
||||
ain->nr_globals++;
|
||||
return &ain->globals[no];
|
||||
}
|
||||
|
||||
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,
|
||||
sizeof(struct ain_initval));
|
||||
ain->global_initvals[ain->nr_initvals++] = *init;
|
||||
}
|
||||
|
||||
static const char *errtab[AIN_MAX_ERROR] = {
|
||||
[AIN_SUCCESS] = "Success",
|
||||
[AIN_FILE_ERROR] = "Error opening AIN file",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "ainedit.h"
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "jaf.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
@@ -32,6 +33,7 @@ static void usage(void)
|
||||
puts("");
|
||||
puts(" -h, --help Display this message and exit");
|
||||
puts(" -c, --code <jam-file> Update the CODE section (assemble .jam file)");
|
||||
puts(" --jaf <jaf-file> Update AIN file from JAF source code");
|
||||
puts(" -j, --json <json-file> Update AIN file from JSON data");
|
||||
puts(" -t, --text <text-file> Update strings/messages");
|
||||
puts(" --transcode <enc> Change the AIN file's text encoding");
|
||||
@@ -48,6 +50,7 @@ extern int text_parse(void);
|
||||
enum {
|
||||
LOPT_HELP = 256,
|
||||
LOPT_CODE,
|
||||
LOPT_JAF,
|
||||
LOPT_JSON,
|
||||
LOPT_TEXT,
|
||||
LOPT_TRANSCODE,
|
||||
@@ -86,6 +89,7 @@ int main(int argc, char *argv[])
|
||||
struct ain *ain;
|
||||
int err = AIN_SUCCESS;
|
||||
const char *code_file = NULL;
|
||||
const char *jaf_file = NULL;
|
||||
const char *decl_file = NULL;
|
||||
const char *text_file = NULL;
|
||||
const char *output_file = NULL;
|
||||
@@ -98,6 +102,7 @@ int main(int argc, char *argv[])
|
||||
static struct option long_options[] = {
|
||||
{ "help", no_argument, 0, LOPT_HELP },
|
||||
{ "code", required_argument, 0, LOPT_CODE },
|
||||
{ "jaf", required_argument, 0, LOPT_JAF },
|
||||
{ "json", required_argument, 0, LOPT_JSON },
|
||||
{ "text", required_argument, 0, LOPT_TEXT },
|
||||
{ "transcode", required_argument, 0, LOPT_TRANSCODE },
|
||||
@@ -123,6 +128,9 @@ int main(int argc, char *argv[])
|
||||
case LOPT_CODE:
|
||||
code_file = optarg;
|
||||
break;
|
||||
case LOPT_JAF:
|
||||
jaf_file = optarg;
|
||||
break;
|
||||
case 'j':
|
||||
case LOPT_JSON:
|
||||
decl_file = optarg;
|
||||
@@ -192,6 +200,10 @@ int main(int argc, char *argv[])
|
||||
read_declarations(decl_file, ain);
|
||||
}
|
||||
|
||||
if (jaf_file) {
|
||||
jaf_compile(ain, jaf_file);
|
||||
}
|
||||
|
||||
if (code_file) {
|
||||
asm_assemble_jam(code_file, ain, flags);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef AINEDIT_JAF_AST_H
|
||||
#define AINEDIT_JAF_AST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "system4/ain.h"
|
||||
|
||||
struct string;
|
||||
|
||||
enum jaf_type {
|
||||
JAF_VOID,
|
||||
JAF_INT,
|
||||
JAF_FLOAT,
|
||||
JAF_STRING,
|
||||
JAF_STRUCT,
|
||||
JAF_ENUM,
|
||||
JAF_TYPEDEF,
|
||||
};
|
||||
|
||||
enum jaf_type_qualifier {
|
||||
JAF_QUAL_CONST = 1,
|
||||
JAF_QUAL_REF = 2
|
||||
};
|
||||
|
||||
enum jaf_expression_type {
|
||||
JAF_EXP_VOID = 0,
|
||||
JAF_EXP_INT,
|
||||
JAF_EXP_FLOAT,
|
||||
JAF_EXP_STRING,
|
||||
JAF_EXP_IDENTIFIER,
|
||||
JAF_EXP_UNARY,
|
||||
JAF_EXP_BINARY,
|
||||
JAF_EXP_TERNARY,
|
||||
};
|
||||
|
||||
enum jaf_operator {
|
||||
JAF_NO_OPERATOR = 0,
|
||||
JAF_AMPERSAND,
|
||||
JAF_UNARY_PLUS,
|
||||
JAF_UNARY_MINUS,
|
||||
JAF_BIT_NOT,
|
||||
JAF_LOG_NOT,
|
||||
JAF_PRE_INC,
|
||||
JAF_PRE_DEC,
|
||||
JAF_POST_INC,
|
||||
JAF_POST_DEC,
|
||||
|
||||
JAF_MULTIPLY,
|
||||
JAF_DIVIDE,
|
||||
JAF_REMAINDER,
|
||||
JAF_PLUS,
|
||||
JAF_MINUS,
|
||||
JAF_LSHIFT,
|
||||
JAF_RSHIFT,
|
||||
JAF_LT,
|
||||
JAF_GT,
|
||||
JAF_LTE,
|
||||
JAF_GTE,
|
||||
JAF_EQ,
|
||||
JAF_BIT_AND,
|
||||
JAF_BIT_XOR,
|
||||
JAF_BIT_IOR,
|
||||
JAF_LOG_AND,
|
||||
JAF_LOG_OR,
|
||||
JAF_ASSIGN,
|
||||
JAF_MUL_ASSIGN,
|
||||
JAF_DIV_ASSIGN,
|
||||
JAF_MOD_ASSIGN,
|
||||
JAF_ADD_ASSIGN,
|
||||
JAF_SUB_ASSIGN,
|
||||
JAF_LSHIFT_ASSIGN,
|
||||
JAF_RSHIFT_ASSIGN,
|
||||
JAF_AND_ASSIGN,
|
||||
JAF_XOR_ASSIGN,
|
||||
JAF_OR_ASSIGN,
|
||||
JAF_REF_ASSIGN,
|
||||
};
|
||||
|
||||
struct jaf_expression {
|
||||
enum jaf_expression_type type;
|
||||
enum jaf_operator op;
|
||||
enum jaf_type derived_type;
|
||||
union {
|
||||
int i;
|
||||
float f;
|
||||
struct string *s;
|
||||
// unary operators
|
||||
struct jaf_expression *expr;
|
||||
// binary operators
|
||||
struct {
|
||||
struct jaf_expression *lhs;
|
||||
struct jaf_expression *rhs;
|
||||
};
|
||||
// ternary operator
|
||||
struct {
|
||||
struct jaf_expression *condition;
|
||||
struct jaf_expression *consequent;
|
||||
struct jaf_expression *alternative;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct jaf_type_specifier {
|
||||
enum jaf_type type;
|
||||
unsigned qualifiers;
|
||||
struct string *name;
|
||||
struct jaf_declaration_list *def;
|
||||
int struct_no;
|
||||
};
|
||||
|
||||
struct jaf_declarator {
|
||||
struct string *name;
|
||||
struct jaf_expression *init;
|
||||
size_t array_rank;
|
||||
size_t *array_dims;
|
||||
};
|
||||
|
||||
struct jaf_declarator_list {
|
||||
size_t nr_decls;
|
||||
struct jaf_declarator **decls;
|
||||
};
|
||||
|
||||
struct jaf_function {
|
||||
// TODO
|
||||
};
|
||||
|
||||
struct jaf_declaration {
|
||||
bool function;
|
||||
struct string *name;
|
||||
struct jaf_type_specifier *type;
|
||||
size_t array_rank;
|
||||
size_t *array_dims;
|
||||
struct jaf_expression *init;
|
||||
struct jaf_function *fun;
|
||||
int var_no;
|
||||
};
|
||||
|
||||
struct jaf_declaration_list {
|
||||
size_t nr_decls;
|
||||
struct jaf_declaration **decls;
|
||||
};
|
||||
|
||||
struct jaf_expression *jaf_integer(struct string *text);
|
||||
struct jaf_expression *jaf_float(struct string *text);
|
||||
struct jaf_expression *jaf_string(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);
|
||||
struct jaf_expression *jaf_ternary_expr(struct jaf_expression *test, struct jaf_expression *cons, struct jaf_expression *alt);
|
||||
struct jaf_expression *jaf_seq_expr(struct jaf_expression *head, struct jaf_expression *tail);
|
||||
|
||||
struct jaf_type_specifier *jaf_type(enum jaf_type type);
|
||||
struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_declaration_list *fields);
|
||||
struct jaf_type_specifier *jaf_typedef(struct string *name);
|
||||
|
||||
struct jaf_declarator *jaf_declarator(struct string *name);
|
||||
struct jaf_declarator_list *jaf_declarators(struct jaf_declarator_list *head, struct jaf_declarator *tail);
|
||||
|
||||
struct jaf_declaration_list *jaf_declaration(struct jaf_type_specifier *type, struct jaf_declarator_list *declarators);
|
||||
struct jaf_declaration_list *jaf_type_declaration(struct jaf_type_specifier *type);
|
||||
struct jaf_declaration_list *jaf_declarations(struct jaf_declaration_list *head, struct jaf_declaration_list *tail);
|
||||
|
||||
void jaf_free_expr(struct jaf_expression *expr);
|
||||
|
||||
// jaf_compile.c
|
||||
struct ain *jaf_ain_out;
|
||||
struct jaf_declaration_list *jaf_toplevel;
|
||||
void jaf_compile(struct ain *out, const char *path);
|
||||
void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type);
|
||||
|
||||
// jaf_eval.c
|
||||
struct jaf_expression *jaf_simplify(struct jaf_expression *in);
|
||||
struct jaf_expression *jaf_compute_constexpr(struct jaf_expression *in);
|
||||
|
||||
// jaf_types.c
|
||||
void jaf_check_types(struct jaf_expression *expr, struct jaf_type_specifier *type);
|
||||
|
||||
#endif /* AINEDIT_JAF_AST_H */
|
||||
@@ -0,0 +1,200 @@
|
||||
/* 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 <errno.h>
|
||||
#include "system4.h"
|
||||
#include "system4/string.h"
|
||||
#include "jaf.h"
|
||||
|
||||
static struct jaf_expression *jaf_expr(enum jaf_expression_type type, enum jaf_operator op)
|
||||
{
|
||||
struct jaf_expression *e = xcalloc(1, sizeof(struct jaf_expression));
|
||||
e->type = type;
|
||||
e->op = op;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_integer(struct string *text)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_INT, 0);
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
e->i = strtol(text->text, &endptr, 0);
|
||||
if (errno || *endptr != '\0')
|
||||
ERROR("Invalid integer constant");
|
||||
free_string(text);
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_float(struct string *text)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_FLOAT, 0);
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
e->f = strtof(text->text, &endptr);
|
||||
if (errno || *endptr != '\0')
|
||||
ERROR("Invalid floating point constant");
|
||||
free_string(text);
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_string(struct string *text)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_STRING, 0);
|
||||
e->s = text;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_identifier(struct string *name)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_IDENTIFIER, 0);
|
||||
e->s = name;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_unary_expr(enum jaf_operator op, struct jaf_expression *expr)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_UNARY, op);
|
||||
e->expr = expr;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_binary_expr(enum jaf_operator op, struct jaf_expression *lhs, struct jaf_expression *rhs)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_BINARY, op);
|
||||
e->lhs = lhs;
|
||||
e->rhs = rhs;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_ternary_expr(struct jaf_expression *test, struct jaf_expression *cons, struct jaf_expression *alt)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_TERNARY, 0);
|
||||
e->condition = test;
|
||||
e->consequent = cons;
|
||||
e->alternative = alt;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_seq_expr(struct jaf_expression *head, struct jaf_expression *tail)
|
||||
{
|
||||
ERROR("Sequence expressions not supported");
|
||||
}
|
||||
|
||||
struct jaf_type_specifier *jaf_type(enum jaf_type type)
|
||||
{
|
||||
struct jaf_type_specifier *p = xcalloc(1, sizeof(struct jaf_type_specifier));
|
||||
p->type = type;
|
||||
p->struct_no = -1;
|
||||
return p;
|
||||
}
|
||||
|
||||
struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_declaration_list *fields)
|
||||
{
|
||||
struct jaf_type_specifier *p = jaf_type(JAF_STRUCT);
|
||||
p->name = name;
|
||||
p->def = fields;
|
||||
return p;
|
||||
}
|
||||
|
||||
struct jaf_type_specifier *jaf_typedef(struct string *name)
|
||||
{
|
||||
struct jaf_type_specifier *p = jaf_type(JAF_TYPEDEF);
|
||||
p->name = name;
|
||||
return p;
|
||||
}
|
||||
|
||||
struct jaf_declarator *jaf_declarator(struct string *name)
|
||||
{
|
||||
struct jaf_declarator *d = xcalloc(1, sizeof(struct jaf_declarator));
|
||||
d->name = name;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct jaf_declarator_list *jaf_declarators(struct jaf_declarator_list *head, struct jaf_declarator *tail)
|
||||
{
|
||||
if (!head) {
|
||||
head = xcalloc(1, sizeof(struct jaf_declarator_list));
|
||||
}
|
||||
|
||||
head->decls = xrealloc_array(head->decls, head->nr_decls, head->nr_decls+1, sizeof(struct jaf_declarator*));
|
||||
head->decls[head->nr_decls++] = tail;
|
||||
return head;
|
||||
}
|
||||
|
||||
struct jaf_declaration_list *jaf_declaration(struct jaf_type_specifier *type, struct jaf_declarator_list *declarators)
|
||||
{
|
||||
struct jaf_declaration_list *decls = xcalloc(1, sizeof(struct jaf_declaration_list));
|
||||
decls->nr_decls = declarators->nr_decls;
|
||||
decls->decls = xcalloc(declarators->nr_decls, sizeof(struct jaf_declaration*));
|
||||
for (size_t i = 0; i < declarators->nr_decls; i++) {
|
||||
struct jaf_declaration *decl = xcalloc(1, sizeof(struct jaf_declaration));
|
||||
decl->function = false;
|
||||
decl->name = declarators->decls[i]->name;
|
||||
decl->type = type;
|
||||
decl->init = declarators->decls[i]->init;
|
||||
decls->decls[i] = decl;
|
||||
|
||||
free(declarators->decls[i]);
|
||||
}
|
||||
free(declarators);
|
||||
return decls;
|
||||
}
|
||||
|
||||
struct jaf_declaration_list *jaf_type_declaration(struct jaf_type_specifier *type)
|
||||
{
|
||||
struct jaf_declaration_list *decls = xcalloc(1, sizeof(struct jaf_declaration_list));
|
||||
decls->nr_decls = 1;
|
||||
decls->decls = xcalloc(1, sizeof(struct jaf_declaration*));
|
||||
decls->decls[0] = xcalloc(1, sizeof(struct jaf_declaration));
|
||||
decls->decls[0]->type = type;
|
||||
return decls;
|
||||
}
|
||||
|
||||
|
||||
struct jaf_declaration_list *jaf_declarations(struct jaf_declaration_list *head, struct jaf_declaration_list *tail)
|
||||
{
|
||||
if (!head)
|
||||
return tail;
|
||||
|
||||
size_t nr_decls = head->nr_decls + tail->nr_decls;
|
||||
head->decls = xrealloc_array(head->decls, head->nr_decls, nr_decls, sizeof(struct jaf_toplevel_decl*));
|
||||
|
||||
for (size_t i = 0; i < tail->nr_decls; i++) {
|
||||
head->decls[head->nr_decls+i] = tail->decls[i];
|
||||
}
|
||||
head->nr_decls = nr_decls;
|
||||
|
||||
free(tail);
|
||||
return head;
|
||||
}
|
||||
|
||||
void jaf_free_expr(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->type == JAF_EXP_UNARY) {
|
||||
jaf_free_expr(expr->expr);
|
||||
} else if (expr->type == JAF_EXP_BINARY) {
|
||||
jaf_free_expr(expr->lhs);
|
||||
jaf_free_expr(expr->rhs);
|
||||
} else if (expr->type == JAF_EXP_TERNARY) {
|
||||
jaf_free_expr(expr->condition);
|
||||
jaf_free_expr(expr->consequent);
|
||||
jaf_free_expr(expr->alternative);
|
||||
}
|
||||
free(expr);
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "system4/string.h"
|
||||
#include "ainedit.h"
|
||||
#include "jaf.h"
|
||||
#include "jaf_parser.tab.h"
|
||||
|
||||
FILE *yyin;
|
||||
int yyparse(void);
|
||||
|
||||
struct ain *jaf_ain_out;
|
||||
struct jaf_declaration_list *jaf_toplevel;
|
||||
|
||||
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 define_types(struct ain *ain, struct jaf_declaration *decl);
|
||||
|
||||
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_decls; i++) {
|
||||
define_types(ain, type->def->decls[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void define_types(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
if (!decl)
|
||||
ERROR("DECL IS NULL");
|
||||
if (!decl->type)
|
||||
ERROR("TYPE IS NULL");
|
||||
if (decl->type->type != JAF_STRUCT)
|
||||
return;
|
||||
|
||||
jaf_define_struct(ain, 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(possibly_unused struct ain *ain, struct jaf_expression **expr, struct jaf_type_specifier *type)
|
||||
{
|
||||
jaf_check_types(*expr, type);
|
||||
*expr = jaf_simplify(*expr);
|
||||
}
|
||||
|
||||
static void resolve_types(struct ain *ain, struct jaf_declaration *decl)
|
||||
{
|
||||
if (decl->function)
|
||||
return;
|
||||
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_declaration_list *def = decl->type->def;
|
||||
struct ain_variable *members = xcalloc(def->nr_decls, sizeof(struct ain_variable));
|
||||
for (size_t i = 0; i < def->nr_decls; i++) {
|
||||
members[i].name = encode_text_to_input_format(def->decls[i]->name->text);
|
||||
if (ain->version >= 12)
|
||||
members[i].name2 = strdup("");
|
||||
jaf_to_ain_type(ain, &members[i].type, def->decls[i]->type);
|
||||
}
|
||||
|
||||
struct ain_struct *s = &ain->structures[decl->type->struct_no];
|
||||
s->nr_members = def->nr_decls;
|
||||
s->members = members;
|
||||
}
|
||||
|
||||
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_declaration *decl)
|
||||
{
|
||||
if (decl->function) {
|
||||
WARNING("Functions not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: global constructors/array allocations
|
||||
}
|
||||
|
||||
void jaf_compile(struct ain *out, const char *path)
|
||||
{
|
||||
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");
|
||||
|
||||
// pass 1: typedefs && struct definitions
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) {
|
||||
resolve_types(out, jaf_toplevel->decls[i]);
|
||||
}
|
||||
// pass 2: register globals (names, types)
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) {
|
||||
if (jaf_toplevel->decls[i]->name) {
|
||||
if (jaf_toplevel->decls[i]->function)
|
||||
ERROR("Functions not supported");
|
||||
else
|
||||
add_global(out, jaf_toplevel->decls[i]);
|
||||
}
|
||||
}
|
||||
// pass 3: type analysis & simplification & global initvals (static analysis)
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) {
|
||||
if (jaf_toplevel->decls[i]->init) {
|
||||
analyze_expression(out, &jaf_toplevel->decls[i]->init, jaf_toplevel->decls[i]->type);
|
||||
|
||||
// add initval to ain object
|
||||
struct ain_initval init = { .global_index = jaf_toplevel->decls[i]->var_no };
|
||||
jaf_to_initval(&init, jaf_toplevel->decls[i]->init);
|
||||
ain_add_initval(out, &init);
|
||||
}
|
||||
}
|
||||
// pass 4: generate bytecode
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) {
|
||||
compile_declaration(out, jaf_toplevel->decls[i]);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/* 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 "system4.h"
|
||||
#include "system4/string.h"
|
||||
#include "jaf.h"
|
||||
|
||||
struct jaf_expression *jaf_simplify(struct jaf_expression *in);
|
||||
|
||||
static struct jaf_expression *jaf_simplify_negation(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->type == JAF_EXP_INT) {
|
||||
expr->i = -expr->i;
|
||||
return expr;
|
||||
}
|
||||
if (expr->type == JAF_EXP_FLOAT) {
|
||||
expr->f = -expr->f;
|
||||
return expr;
|
||||
}
|
||||
|
||||
return jaf_unary_expr(JAF_UNARY_MINUS, expr);
|
||||
}
|
||||
|
||||
static struct jaf_expression *jaf_simplify_bitnot(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->type == JAF_EXP_INT) {
|
||||
expr->i = ~expr->i;
|
||||
return expr;
|
||||
}
|
||||
|
||||
return jaf_unary_expr(JAF_BIT_NOT, expr);
|
||||
}
|
||||
|
||||
static struct jaf_expression *jaf_simplify_lognot(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->type == JAF_EXP_INT) {
|
||||
expr->i = !expr->i;
|
||||
return expr;
|
||||
}
|
||||
|
||||
return jaf_unary_expr(JAF_LOG_NOT, expr);
|
||||
}
|
||||
|
||||
static struct jaf_expression *jaf_simplify_unary(struct jaf_expression *in)
|
||||
{
|
||||
struct jaf_expression *out = jaf_simplify(in->expr);
|
||||
switch (in->op) {
|
||||
case JAF_UNARY_PLUS:
|
||||
return out;
|
||||
case JAF_UNARY_MINUS:
|
||||
return jaf_simplify_negation(out);
|
||||
case JAF_BIT_NOT:
|
||||
return jaf_simplify_bitnot(out);
|
||||
case JAF_LOG_NOT:
|
||||
return jaf_simplify_lognot(out);
|
||||
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);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ERROR("Invalid unary operator");
|
||||
}
|
||||
|
||||
static void jaf_normalize_for_arithmetic(struct jaf_expression *lhs, struct jaf_expression *rhs)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#define SIMPLIFY_ARITHMETIC_FUN(name, op_name, op) \
|
||||
static struct jaf_expression *name(struct jaf_expression *lhs, struct jaf_expression *rhs) \
|
||||
{ \
|
||||
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 (lhs->type == JAF_EXP_FLOAT && rhs->type == JAF_EXP_FLOAT) { \
|
||||
lhs->f = lhs->f op rhs->f; \
|
||||
free(rhs); \
|
||||
return lhs; \
|
||||
} \
|
||||
return jaf_binary_expr(op_name, lhs, rhs); \
|
||||
}
|
||||
|
||||
#define SIMPLIFY_INTEGER_FUN(name, op_name, op) \
|
||||
static struct jaf_expression *name(struct jaf_expression *lhs, struct jaf_expression *rhs) \
|
||||
{ \
|
||||
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; \
|
||||
} \
|
||||
return jaf_binary_expr(op_name, lhs, rhs); \
|
||||
}
|
||||
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_multiply, JAF_MULTIPLY, *)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_divide, JAF_DIVIDE, /)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_remainder, JAF_REMAINDER, %)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_plus, JAF_PLUS, +) // TODO: string concatentation
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_minus, JAF_MINUS, -)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_lshift, JAF_LSHIFT, <<)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_rshift, JAF_RSHIFT, >>)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_lt, JAF_LT, <)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_gt, JAF_GT, >)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_lte, JAF_LTE, <=)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_gte, JAF_GTE, >=)
|
||||
SIMPLIFY_ARITHMETIC_FUN(jaf_simplify_eq, JAF_EQ, ==)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_bitand, JAF_BIT_AND, &)
|
||||
SIMPLIFY_INTEGER_FUN (jaf_simplify_bitxor, JAF_BIT_XOR, ^)
|
||||
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)
|
||||
{
|
||||
enum jaf_operator op = in->op;
|
||||
struct jaf_expression *lhs = jaf_simplify(in->lhs);
|
||||
struct jaf_expression *rhs = jaf_simplify(in->rhs);
|
||||
free(in);
|
||||
|
||||
switch (op) {
|
||||
case JAF_MULTIPLY:
|
||||
return jaf_simplify_multiply(lhs, rhs);
|
||||
case JAF_DIVIDE:
|
||||
return jaf_simplify_divide(lhs, rhs);
|
||||
case JAF_REMAINDER:
|
||||
return jaf_simplify_remainder(lhs, rhs);
|
||||
case JAF_PLUS:
|
||||
return jaf_simplify_plus(lhs, rhs);
|
||||
case JAF_MINUS:
|
||||
return jaf_simplify_minus(lhs, rhs);
|
||||
case JAF_LSHIFT:
|
||||
return jaf_simplify_lshift(lhs, rhs);
|
||||
case JAF_RSHIFT:
|
||||
return jaf_simplify_rshift(lhs, rhs);
|
||||
case JAF_LT:
|
||||
return jaf_simplify_lt(lhs, rhs);
|
||||
case JAF_GT:
|
||||
return jaf_simplify_gt(lhs, rhs);
|
||||
case JAF_LTE:
|
||||
return jaf_simplify_lte(lhs, rhs);
|
||||
case JAF_GTE:
|
||||
return jaf_simplify_gte(lhs, rhs);
|
||||
case JAF_EQ:
|
||||
return jaf_simplify_eq(lhs, rhs);
|
||||
case JAF_BIT_AND:
|
||||
return jaf_simplify_bitand(lhs, rhs);
|
||||
case JAF_BIT_XOR:
|
||||
return jaf_simplify_bitxor(lhs, rhs);
|
||||
case JAF_BIT_IOR:
|
||||
return jaf_simplify_bitior(lhs, rhs);
|
||||
case JAF_LOG_AND:
|
||||
return jaf_simplify_logand(lhs, rhs);
|
||||
case JAF_LOG_OR:
|
||||
return jaf_simplify_logor(lhs, rhs);
|
||||
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:
|
||||
return jaf_binary_expr(op, lhs, rhs);
|
||||
default:
|
||||
ERROR("Invalid binary operator");
|
||||
}
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_simplify_ternary(struct jaf_expression *in)
|
||||
{
|
||||
in->condition = jaf_simplify(in->condition);
|
||||
in->consequent = jaf_simplify(in->consequent);
|
||||
in->alternative = jaf_simplify(in->alternative);
|
||||
|
||||
if (in->condition->type == JAF_EXP_INT) {
|
||||
if (in->condition->i) {
|
||||
jaf_free_expr(in->condition);
|
||||
jaf_free_expr(in->alternative);
|
||||
free(in);
|
||||
return in->consequent;
|
||||
} else {
|
||||
jaf_free_expr(in->condition);
|
||||
jaf_free_expr(in->consequent);
|
||||
free(in);
|
||||
return in->alternative;
|
||||
}
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simplify an expression by evaluating the constant parts.
|
||||
*/
|
||||
struct jaf_expression *jaf_simplify(struct jaf_expression *in)
|
||||
{
|
||||
switch (in->type) {
|
||||
case JAF_EXP_VOID:
|
||||
case JAF_EXP_INT:
|
||||
case JAF_EXP_FLOAT:
|
||||
case JAF_EXP_STRING:
|
||||
case JAF_EXP_IDENTIFIER:
|
||||
return in;
|
||||
case JAF_EXP_UNARY:
|
||||
return jaf_simplify_unary(in);
|
||||
case JAF_EXP_BINARY:
|
||||
return jaf_simplify_binary(in);
|
||||
case JAF_EXP_TERNARY:
|
||||
return jaf_simplify_ternary(in);
|
||||
}
|
||||
ERROR("Invalid expression type");
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_compute_constexpr(struct jaf_expression *in)
|
||||
{
|
||||
struct jaf_expression *out = jaf_simplify(in);
|
||||
switch (out->type) {
|
||||
case JAF_EXP_INT:
|
||||
case JAF_EXP_FLOAT:
|
||||
case JAF_EXP_STRING:
|
||||
return out;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/* 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/>.
|
||||
*
|
||||
* Based on ANSI C grammar from http://www.quut.com/c/ANSI-C-grammar-l-2011.html
|
||||
*/
|
||||
|
||||
%e 1019
|
||||
%p 2807
|
||||
%n 371
|
||||
%k 284
|
||||
%a 1213
|
||||
%o 1117
|
||||
|
||||
O [0-7]
|
||||
D [0-9]
|
||||
NZ [1-9]
|
||||
L [a-zA-Z_]
|
||||
A [a-zA-Z_0-9]
|
||||
H [a-fA-F0-9]
|
||||
HP (0[xX])
|
||||
E ([Ee][+-]?{D}+)
|
||||
P ([Pp][+-]?{D}+)
|
||||
FS (f|F|l|L)
|
||||
IS (((u|U)(l|L|ll|LL)?)|((l|L|ll|LL)(u|U)?))
|
||||
CP (u|U|L)
|
||||
SP (u8|u|U|L)
|
||||
ES (\\(['"\?\\abfnrtv]|[0-7]{1,3}|x[a-fA-F0-9]+))
|
||||
WS [ \t\v\n\f]
|
||||
|
||||
%{
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#include <stdio.h>
|
||||
#include "system4/string.h"
|
||||
#include "jaf_parser.tab.h"
|
||||
|
||||
extern void yyerror(const char *); /* prints grammar violation message */
|
||||
|
||||
extern int sym_type(const char *); /* returns type from symbol table */
|
||||
|
||||
#define sym_type(identifier) IDENTIFIER /* with no symbol table, fake it */
|
||||
|
||||
static void comment(void);
|
||||
static int check_type(void);
|
||||
|
||||
#define RETURN_STRING(tok_type) yylval.string = make_string(yytext, yyleng); return tok_type
|
||||
%}
|
||||
|
||||
%%
|
||||
"/*" { comment(); }
|
||||
"//".* { /* consume //-comment */ }
|
||||
|
||||
"break" { return(BREAK); }
|
||||
"case" { return(CASE); }
|
||||
"char" { return(CHAR); }
|
||||
"const" { return(CONST); }
|
||||
"continue" { return(CONTINUE); }
|
||||
"default" { return(DEFAULT); }
|
||||
"do" { return(DO); }
|
||||
"else" { return(ELSE); }
|
||||
"enum" { return(ENUM); }
|
||||
"float" { return(FLOAT); }
|
||||
"for" { return(FOR); }
|
||||
"goto" { return(GOTO); }
|
||||
"if" { return(IF); }
|
||||
"int" { return(INT); }
|
||||
"long" { return(LONG); }
|
||||
"return" { return(SYM_RETURN); }
|
||||
"string" { return(STRING); }
|
||||
"struct" { return(STRUCT); }
|
||||
"switch" { return(SYM_SWITCH); }
|
||||
"union" { return(UNION); }
|
||||
"void" { return(VOID); }
|
||||
"while" { return(WHILE); }
|
||||
"bool" { return BOOL; }
|
||||
"__func__" { return FUNC_NAME; }
|
||||
"ref" { return SYM_REF; }
|
||||
|
||||
{L}{A}* { return check_type(); }
|
||||
|
||||
{HP}{H}+{IS}? { RETURN_STRING(I_CONSTANT); }
|
||||
{NZ}{D}*{IS}? { RETURN_STRING(I_CONSTANT); }
|
||||
"0"{O}*{IS}? { RETURN_STRING(I_CONSTANT); }
|
||||
{CP}?"'"([^'\\\n]|{ES})+"'" { RETURN_STRING(I_CONSTANT); }
|
||||
|
||||
{D}+{E}{FS}? { RETURN_STRING(F_CONSTANT); }
|
||||
{D}*"."{D}+{E}?{FS}? { RETURN_STRING(F_CONSTANT); }
|
||||
{D}+"."{E}?{FS}? { RETURN_STRING(F_CONSTANT); }
|
||||
{HP}{H}+{P}{FS}? { RETURN_STRING(F_CONSTANT); }
|
||||
{HP}{H}*"."{H}+{P}{FS}? { RETURN_STRING(F_CONSTANT); }
|
||||
{HP}{H}+"."{P}{FS}? { RETURN_STRING(F_CONSTANT); }
|
||||
|
||||
({SP}?\"([^"\\\n]|{ES})*\"{WS}*)+ { RETURN_STRING(STRING_LITERAL); }
|
||||
|
||||
"..." { return ELLIPSIS; }
|
||||
">>=" { return RIGHT_ASSIGN; }
|
||||
"<<=" { return LEFT_ASSIGN; }
|
||||
"+=" { return ADD_ASSIGN; }
|
||||
"-=" { return SUB_ASSIGN; }
|
||||
"*=" { return MUL_ASSIGN; }
|
||||
"/=" { return DIV_ASSIGN; }
|
||||
"%=" { return MOD_ASSIGN; }
|
||||
"&=" { return AND_ASSIGN; }
|
||||
"^=" { return XOR_ASSIGN; }
|
||||
"|=" { return OR_ASSIGN; }
|
||||
"<-" { return REF_ASSIGN; }
|
||||
">>" { return RIGHT_OP; }
|
||||
"<<" { return LEFT_OP; }
|
||||
"++" { return INC_OP; }
|
||||
"--" { return DEC_OP; }
|
||||
"&&" { return AND_OP; }
|
||||
"||" { return OR_OP; }
|
||||
"<=" { return LE_OP; }
|
||||
">=" { return GE_OP; }
|
||||
"==" { return EQ_OP; }
|
||||
"!=" { return NE_OP; }
|
||||
";" { return ';'; }
|
||||
("{"|"<%") { return '{'; }
|
||||
("}"|"%>") { return '}'; }
|
||||
"," { return ','; }
|
||||
":" { return ':'; }
|
||||
"=" { return '='; }
|
||||
"(" { return '('; }
|
||||
")" { return ')'; }
|
||||
("["|"<:") { return '['; }
|
||||
("]"|":>") { return ']'; }
|
||||
"." { return '.'; }
|
||||
"&" { return '&'; }
|
||||
"!" { return '!'; }
|
||||
"~" { return '~'; }
|
||||
"-" { return '-'; }
|
||||
"+" { return '+'; }
|
||||
"*" { return '*'; }
|
||||
"/" { return '/'; }
|
||||
"%" { return '%'; }
|
||||
"<" { return '<'; }
|
||||
">" { return '>'; }
|
||||
"^" { return '^'; }
|
||||
"|" { return '|'; }
|
||||
"?" { return '?'; }
|
||||
|
||||
{WS}+ { /* whitespace separates tokens */ }
|
||||
. { /* discard bad characters */ }
|
||||
|
||||
%%
|
||||
|
||||
int yywrap(void) /* called at end of input */
|
||||
{
|
||||
return 1; /* terminate now */
|
||||
}
|
||||
|
||||
static void comment(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = input()) != 0)
|
||||
if (c == '*')
|
||||
{
|
||||
while ((c = input()) == '*')
|
||||
;
|
||||
|
||||
if (c == '/')
|
||||
return;
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
yyerror("unterminated comment");
|
||||
}
|
||||
|
||||
static int check_type(void)
|
||||
{
|
||||
switch (sym_type(yytext))
|
||||
{
|
||||
case TYPEDEF_NAME: /* previously defined */
|
||||
RETURN_STRING(TYPEDEF_NAME);
|
||||
case ENUMERATION_CONSTANT: /* previously defined */
|
||||
RETURN_STRING(ENUMERATION_CONSTANT);
|
||||
default: /* includes undefined */
|
||||
RETURN_STRING(IDENTIFIER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
/* 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/>.
|
||||
*
|
||||
* Based on ANSI C grammar from http://www.quut.com/c/ANSI-C-grammar-l-2011.html
|
||||
*/
|
||||
|
||||
%{
|
||||
#include "system4.h"
|
||||
#include "system4/ain.h"
|
||||
#include "jaf.h"
|
||||
extern int yylex();
|
||||
void yyerror(const char *s);
|
||||
%}
|
||||
|
||||
%union {
|
||||
int token;
|
||||
struct string *string;
|
||||
struct jaf_expression *expression;
|
||||
struct jaf_type_specifier *type;
|
||||
struct jaf_declarator *declarator;
|
||||
struct jaf_declarator_list *declarators;
|
||||
struct jaf_declaration_list *declarations;
|
||||
}
|
||||
|
||||
%token <string> I_CONSTANT F_CONSTANT STRING_LITERAL
|
||||
%token <string> IDENTIFIER TYPEDEF_NAME ENUMERATION_CONSTANT
|
||||
|
||||
%token <token> INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
|
||||
%token <token> AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
||||
%token <token> SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
|
||||
%token <token> XOR_ASSIGN OR_ASSIGN
|
||||
%token <token> SYM_REF REF_ASSIGN FUNC_NAME
|
||||
|
||||
%token <token> CONST
|
||||
%token <token> BOOL CHAR INT LONG FLOAT VOID STRING
|
||||
%token <token> STRUCT UNION ENUM ELLIPSIS
|
||||
|
||||
%token CASE DEFAULT IF ELSE SYM_SWITCH WHILE DO FOR GOTO CONTINUE BREAK SYM_RETURN
|
||||
|
||||
%type <token> unary_operator assignment_operator type_qualifier
|
||||
%type <string> string param_identifer
|
||||
%type <expression> initializer
|
||||
%type <expression> postfix_expression unary_expression cast_expression
|
||||
%type <expression> multiplicative_expression additive_expression shift_expression
|
||||
%type <expression> relational_expression equality_expression and_expression
|
||||
%type <expression> exclusive_or_expression inclusive_or_expression
|
||||
%type <expression> logical_and_expression logical_or_expression
|
||||
%type <expression> conditional_expression assignment_expression
|
||||
%type <expression> expression constant_expression primary_expression constant
|
||||
%type <type> type_specifier struct_specifier declaration_specifiers
|
||||
%type <declarator> init_declarator declarator
|
||||
%type <declarators> init_declarator_list struct_declarator_list
|
||||
%type <declarations> translation_unit external_declaration declaration
|
||||
%type <declarations> struct_declaration struct_declaration_list
|
||||
|
||||
/*
|
||||
* Shift-reduce conflicts:
|
||||
* 1. dangling else
|
||||
*/
|
||||
%expect 1
|
||||
|
||||
%start toplevel
|
||||
%%
|
||||
|
||||
primary_expression
|
||||
: IDENTIFIER { $$ = jaf_identifier($1); }
|
||||
| constant { $$ = $1; }
|
||||
| string { $$ = jaf_string($1); }
|
||||
| '(' expression ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
constant
|
||||
: I_CONSTANT { $$ = jaf_integer($1); } /* includes character_constant */
|
||||
| F_CONSTANT { $$ = jaf_float($1); }
|
||||
| ENUMERATION_CONSTANT { ERROR("Enums not supported"); } /* after it has been defined as such */
|
||||
;
|
||||
|
||||
enumeration_constant /* before it has been defined as such */
|
||||
: IDENTIFIER
|
||||
;
|
||||
|
||||
string
|
||||
: STRING_LITERAL { $$ = $1; }
|
||||
| FUNC_NAME { ERROR("__func__ not supported"); }
|
||||
// | STRING '(' assignment_expression ')'
|
||||
;
|
||||
|
||||
postfix_expression
|
||||
: primary_expression { $$ = $1; }
|
||||
| postfix_expression '[' expression ']' { ERROR("Arrays not supported"); }
|
||||
| postfix_expression '(' ')' { ERROR("Function calls not supported"); }
|
||||
| type_specifier '(' expression ')' { ERROR("Cast not supported"); }
|
||||
| postfix_expression '(' argument_expression_list ')' { ERROR("Function calls not supported"); }
|
||||
| postfix_expression '.' IDENTIFIER { ERROR("Struct members not supported"); }
|
||||
| postfix_expression INC_OP { $$ = jaf_unary_expr(JAF_POST_INC, $1); }
|
||||
| postfix_expression DEC_OP { $$ = jaf_unary_expr(JAF_POST_DEC, $1); }
|
||||
// | '(' type_specifier ')' '{' initializer_list '}'
|
||||
// | '(' type_specifier ')' '{' initializer_list ',' '}'
|
||||
;
|
||||
|
||||
argument_expression_list
|
||||
: assignment_expression
|
||||
| argument_expression_list ',' assignment_expression
|
||||
;
|
||||
|
||||
unary_expression
|
||||
: postfix_expression { $$ = $1; }
|
||||
| INC_OP unary_expression { $$ = jaf_unary_expr(JAF_PRE_INC, $2); }
|
||||
| DEC_OP unary_expression { $$ = jaf_unary_expr(JAF_PRE_DEC, $2); }
|
||||
| unary_operator cast_expression { $$ = jaf_unary_expr($1, $2); }
|
||||
;
|
||||
|
||||
unary_operator
|
||||
: '&' { $$ = JAF_AMPERSAND; }
|
||||
| '+' { $$ = JAF_UNARY_PLUS; }
|
||||
| '-' { $$ = JAF_UNARY_MINUS; }
|
||||
| '~' { $$ = JAF_BIT_NOT; }
|
||||
| '!' { $$ = JAF_LOG_NOT; }
|
||||
;
|
||||
|
||||
cast_expression
|
||||
: unary_expression { $$ = $1; }
|
||||
| '(' type_specifier ')' cast_expression { ERROR("Cast not supported"); }
|
||||
;
|
||||
|
||||
multiplicative_expression
|
||||
: cast_expression { $$ = $1; }
|
||||
| multiplicative_expression '*' cast_expression { $$ = jaf_binary_expr(JAF_MULTIPLY, $1, $3); }
|
||||
| multiplicative_expression '/' cast_expression { $$ = jaf_binary_expr(JAF_DIVIDE, $1, $3); }
|
||||
| multiplicative_expression '%' cast_expression { $$ = jaf_binary_expr(JAF_REMAINDER, $1, $3); }
|
||||
;
|
||||
|
||||
additive_expression
|
||||
: multiplicative_expression { $$ = $1; }
|
||||
| additive_expression '+' multiplicative_expression { $$ = jaf_binary_expr(JAF_PLUS, $1, $3); }
|
||||
| additive_expression '-' multiplicative_expression { $$ = jaf_binary_expr(JAF_MINUS, $1, $3); }
|
||||
;
|
||||
|
||||
shift_expression
|
||||
: additive_expression { $$ = $1; }
|
||||
| shift_expression LEFT_OP additive_expression { $$ = jaf_binary_expr(JAF_LSHIFT, $1, $3); }
|
||||
| shift_expression RIGHT_OP additive_expression { $$ = jaf_binary_expr(JAF_RSHIFT, $1, $3); }
|
||||
;
|
||||
|
||||
relational_expression
|
||||
: shift_expression { $$ = $1; }
|
||||
| relational_expression '<' shift_expression { $$ = jaf_binary_expr(JAF_LT, $1, $3); }
|
||||
| relational_expression '>' shift_expression { $$ = jaf_binary_expr(JAF_GT, $1, $3); }
|
||||
| relational_expression LE_OP shift_expression { $$ = jaf_binary_expr(JAF_LTE, $1, $3); }
|
||||
| relational_expression GE_OP shift_expression { $$ = jaf_binary_expr(JAF_GTE, $1, $3); }
|
||||
;
|
||||
|
||||
equality_expression
|
||||
: relational_expression { $$ = $1; }
|
||||
| equality_expression EQ_OP relational_expression { $$ = jaf_binary_expr(JAF_EQ, $1, $3); }
|
||||
| equality_expression NE_OP relational_expression { $$ = jaf_unary_expr(JAF_LOG_NOT, jaf_binary_expr(JAF_EQ, $1, $3)); }
|
||||
;
|
||||
|
||||
and_expression
|
||||
: equality_expression { $$ = $1; }
|
||||
| and_expression '&' equality_expression { $$ = jaf_binary_expr(JAF_BIT_AND, $1, $3); }
|
||||
;
|
||||
|
||||
exclusive_or_expression
|
||||
: and_expression { $$ = $1; }
|
||||
| exclusive_or_expression '^' and_expression { $$ = jaf_binary_expr(JAF_BIT_XOR, $1, $3); }
|
||||
;
|
||||
|
||||
inclusive_or_expression
|
||||
: exclusive_or_expression { $$ = $1; }
|
||||
| inclusive_or_expression '|' exclusive_or_expression { $$ = jaf_binary_expr(JAF_BIT_IOR, $1, $3); }
|
||||
;
|
||||
|
||||
logical_and_expression
|
||||
: inclusive_or_expression { $$ = $1; }
|
||||
| logical_and_expression AND_OP inclusive_or_expression { $$ = jaf_binary_expr(JAF_LOG_AND, $1, $3); }
|
||||
;
|
||||
|
||||
logical_or_expression
|
||||
: logical_and_expression { $$ = $1; }
|
||||
| logical_or_expression OR_OP logical_and_expression { $$ = jaf_binary_expr(JAF_LOG_OR, $1, $3); }
|
||||
;
|
||||
|
||||
conditional_expression
|
||||
: logical_or_expression { $$ = $1; }
|
||||
| logical_or_expression '?' expression ':' conditional_expression { $$ = jaf_ternary_expr($1, $3, $5); }
|
||||
;
|
||||
|
||||
assignment_expression
|
||||
: conditional_expression { $$ = $1; }
|
||||
| unary_expression assignment_operator assignment_expression { $$ = jaf_binary_expr($2, $1, $3); }
|
||||
;
|
||||
|
||||
assignment_operator
|
||||
: '=' { $$ = JAF_ASSIGN; }
|
||||
| MUL_ASSIGN { $$ = JAF_MUL_ASSIGN; }
|
||||
| DIV_ASSIGN { $$ = JAF_DIV_ASSIGN; }
|
||||
| MOD_ASSIGN { $$ = JAF_MOD_ASSIGN; }
|
||||
| ADD_ASSIGN { $$ = JAF_ADD_ASSIGN; }
|
||||
| SUB_ASSIGN { $$ = JAF_SUB_ASSIGN; }
|
||||
| LEFT_ASSIGN { $$ = JAF_LSHIFT_ASSIGN; }
|
||||
| RIGHT_ASSIGN { $$ = JAF_RSHIFT_ASSIGN; }
|
||||
| AND_ASSIGN { $$ = JAF_AND_ASSIGN; }
|
||||
| XOR_ASSIGN { $$ = JAF_XOR_ASSIGN; }
|
||||
| OR_ASSIGN { $$ = JAF_OR_ASSIGN; }
|
||||
| REF_ASSIGN { $$ = JAF_REF_ASSIGN; }
|
||||
;
|
||||
|
||||
expression
|
||||
: assignment_expression { $$ = $1; }
|
||||
| expression ',' assignment_expression { $$ = jaf_seq_expr($1, $3); }
|
||||
;
|
||||
|
||||
constant_expression
|
||||
: conditional_expression { $$ = $1; } /* with constraints */
|
||||
;
|
||||
|
||||
declaration
|
||||
: declaration_specifiers ';' { $$ = jaf_type_declaration($1); }
|
||||
| declaration_specifiers init_declarator_list ';' { $$ = jaf_declaration($1, $2); }
|
||||
;
|
||||
|
||||
declaration_specifiers
|
||||
: type_qualifier type_specifier { $$ = $2; $$->qualifiers = $1; }
|
||||
| type_specifier { $$ = $1; }
|
||||
;
|
||||
|
||||
init_declarator_list
|
||||
: init_declarator { $$ = jaf_declarators(NULL, $1); }
|
||||
| init_declarator_list ',' init_declarator { $$ = jaf_declarators($1, $3); }
|
||||
;
|
||||
|
||||
init_declarator
|
||||
: declarator '=' initializer { $$ = $1; $$->init = $3; }
|
||||
| declarator { $$ = $1; }
|
||||
;
|
||||
|
||||
type_specifier
|
||||
: VOID { $$ = jaf_type(JAF_VOID); }
|
||||
| CHAR { $$ = jaf_type(JAF_INT); }
|
||||
| INT { $$ = jaf_type(JAF_INT); }
|
||||
| LONG { $$ = jaf_type(JAF_INT); }
|
||||
| FLOAT { $$ = jaf_type(JAF_FLOAT); }
|
||||
| BOOL { $$ = jaf_type(JAF_INT); }
|
||||
| STRING { $$ = jaf_type(JAF_STRING); }
|
||||
| struct_specifier { $$ = $1; }
|
||||
| enum_specifier { ERROR("Enums not supported"); }
|
||||
| TYPEDEF_NAME { $$ = jaf_typedef($1); } /* after it has been defined as such */
|
||||
;
|
||||
|
||||
struct_specifier
|
||||
: STRUCT param_identifer '{' struct_declaration_list '}' { $$ = jaf_struct($2, $4); jaf_define_struct(jaf_ain_out, $$); }
|
||||
;
|
||||
|
||||
param_identifer
|
||||
: IDENTIFIER { $$ = $1; }
|
||||
| IDENTIFIER '<' type_parameter_list '>' { ERROR("Type parameters not supported"); }
|
||||
;
|
||||
|
||||
type_parameter_list
|
||||
: type_specifier
|
||||
| type_parameter_list ',' type_specifier
|
||||
;
|
||||
|
||||
struct_declaration_list
|
||||
: struct_declaration { $$ = $1; }
|
||||
| struct_declaration_list struct_declaration { $$ = jaf_declarations($1, $2); }
|
||||
;
|
||||
|
||||
struct_declaration
|
||||
// : type_specifier ';' /* for anonymous struct/union */
|
||||
: type_specifier struct_declarator_list ';' { $$ = jaf_declaration($1, $2); }
|
||||
;
|
||||
|
||||
struct_declarator_list
|
||||
: declarator { $$ = jaf_declarators(NULL, $1); }
|
||||
| struct_declarator_list ',' declarator { $$ = jaf_declarators($1, $3); }
|
||||
;
|
||||
|
||||
enum_specifier
|
||||
: ENUM '{' enumerator_list '}'
|
||||
| ENUM '{' enumerator_list ',' '}'
|
||||
| ENUM IDENTIFIER '{' enumerator_list '}'
|
||||
| ENUM IDENTIFIER '{' enumerator_list ',' '}'
|
||||
;
|
||||
|
||||
enumerator_list
|
||||
: enumerator
|
||||
| enumerator_list ',' enumerator
|
||||
;
|
||||
|
||||
enumerator /* identifiers must be flagged as ENUMERATION_CONSTANT */
|
||||
: enumeration_constant '=' constant_expression
|
||||
| enumeration_constant
|
||||
;
|
||||
|
||||
type_qualifier
|
||||
: CONST { $$ = JAF_QUAL_CONST; }
|
||||
| SYM_REF { $$ = JAF_QUAL_REF; }
|
||||
;
|
||||
|
||||
declarator
|
||||
: IDENTIFIER { $$ = jaf_declarator($1); }
|
||||
// | '(' declarator ')' // XXX: causes shift-reduce conflict with function-like casts (e.g. "string(identifier)")
|
||||
| array_allocation { ERROR("Arrays not supported"); }
|
||||
| IDENTIFIER '(' parameter_type_list ')' { ERROR("Function declarator not supported"); } // ??? remove?
|
||||
| IDENTIFIER '(' ')' { ERROR("Function declarator not supported"); } // ??? remove?
|
||||
;
|
||||
|
||||
array_allocation
|
||||
: IDENTIFIER '[' constant ']'
|
||||
| array_allocation '[' constant ']'
|
||||
;
|
||||
|
||||
parameter_type_list
|
||||
: parameter_list ',' ELLIPSIS
|
||||
| parameter_list
|
||||
;
|
||||
|
||||
parameter_list
|
||||
: parameter_declaration
|
||||
| parameter_list ',' parameter_declaration
|
||||
;
|
||||
|
||||
parameter_declaration
|
||||
: declaration_specifiers declarator
|
||||
| declaration_specifiers
|
||||
;
|
||||
|
||||
initializer
|
||||
: '{' initializer_list '}' { $$ = NULL; }
|
||||
| '{' initializer_list ',' '}' { $$ = NULL; }
|
||||
| assignment_expression { $$ = $1; }
|
||||
;
|
||||
|
||||
initializer_list
|
||||
: designation initializer
|
||||
| initializer
|
||||
| initializer_list ',' designation initializer
|
||||
| initializer_list ',' initializer
|
||||
;
|
||||
|
||||
designation
|
||||
: designator_list '='
|
||||
;
|
||||
|
||||
designator_list
|
||||
: designator
|
||||
| designator_list designator
|
||||
;
|
||||
|
||||
designator
|
||||
: '[' constant_expression ']'
|
||||
| '.' IDENTIFIER
|
||||
;
|
||||
|
||||
statement
|
||||
: labeled_statement
|
||||
| compound_statement
|
||||
| expression_statement
|
||||
| selection_statement
|
||||
| iteration_statement
|
||||
| jump_statement
|
||||
;
|
||||
|
||||
labeled_statement
|
||||
: IDENTIFIER ':' statement
|
||||
| CASE constant_expression ':' statement
|
||||
| DEFAULT ':' statement
|
||||
;
|
||||
|
||||
compound_statement
|
||||
: '{' '}'
|
||||
| '{' block_item_list '}'
|
||||
;
|
||||
|
||||
block_item_list
|
||||
: block_item
|
||||
| block_item_list block_item
|
||||
;
|
||||
|
||||
block_item
|
||||
: declaration
|
||||
| statement
|
||||
;
|
||||
|
||||
expression_statement
|
||||
: ';'
|
||||
| expression ';'
|
||||
;
|
||||
|
||||
selection_statement
|
||||
: IF '(' expression ')' statement ELSE statement
|
||||
| IF '(' expression ')' statement
|
||||
| SYM_SWITCH '(' expression ')' statement
|
||||
;
|
||||
|
||||
iteration_statement
|
||||
: WHILE '(' expression ')' statement
|
||||
| DO statement WHILE '(' expression ')' ';'
|
||||
| FOR '(' expression_statement expression_statement ')' statement
|
||||
| FOR '(' expression_statement expression_statement expression ')' statement
|
||||
| FOR '(' declaration expression_statement ')' statement
|
||||
| FOR '(' declaration expression_statement expression ')' statement
|
||||
;
|
||||
|
||||
jump_statement
|
||||
: GOTO IDENTIFIER ';'
|
||||
| CONTINUE ';'
|
||||
| BREAK ';'
|
||||
| SYM_RETURN ';'
|
||||
| SYM_RETURN expression ';'
|
||||
;
|
||||
|
||||
toplevel
|
||||
: translation_unit { jaf_toplevel = $1; }
|
||||
;
|
||||
|
||||
translation_unit
|
||||
: external_declaration { $$ = jaf_declarations(NULL, $1); }
|
||||
| translation_unit external_declaration { $$ = jaf_declarations($1, $2); }
|
||||
;
|
||||
|
||||
external_declaration
|
||||
: function_definition { ERROR("Functions not yet supported"); }
|
||||
| declaration { $$ = $1; }
|
||||
;
|
||||
|
||||
function_definition
|
||||
: declaration_specifiers declarator compound_statement
|
||||
;
|
||||
|
||||
%%
|
||||
#include <stdio.h>
|
||||
|
||||
void yyerror(const char *s)
|
||||
{
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "*** %s\n", s);
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/* 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 "system4.h"
|
||||
#include "jaf.h"
|
||||
|
||||
// TODO: better error messages
|
||||
#define TYPE_ERROR(expr, expected) ERROR("Type error")
|
||||
#define TYPE_CHECK(expr, expected) { if (expr->derived_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 void jaf_derive_types(struct jaf_expression *expr);
|
||||
|
||||
static enum jaf_type jaf_type_check_numeric(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->derived_type != JAF_INT && expr->derived_type != JAF_FLOAT)
|
||||
TYPE_ERROR(expr, JAF_INT);
|
||||
return expr->derived_type;
|
||||
}
|
||||
|
||||
static enum jaf_type jaf_type_check_int(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->derived_type != JAF_INT)
|
||||
TYPE_ERROR(expr, JAF_INT);
|
||||
return expr->derived_type;
|
||||
}
|
||||
|
||||
static enum jaf_type jaf_merge_types(enum jaf_type a, enum jaf_type b)
|
||||
{
|
||||
if (a == b)
|
||||
return a;
|
||||
if (a == JAF_INT && b == JAF_FLOAT)
|
||||
return JAF_FLOAT;
|
||||
if (a == JAF_FLOAT && b == JAF_INT)
|
||||
return JAF_FLOAT;
|
||||
ERROR("Incompatible types");
|
||||
}
|
||||
|
||||
static enum jaf_type jaf_check_types_unary(struct jaf_expression *expr)
|
||||
{
|
||||
jaf_derive_types(expr->expr);
|
||||
switch (expr->op) {
|
||||
case JAF_UNARY_PLUS:
|
||||
case JAF_UNARY_MINUS:
|
||||
case JAF_PRE_INC:
|
||||
case JAF_PRE_DEC:
|
||||
case JAF_POST_INC:
|
||||
case JAF_POST_DEC:
|
||||
return jaf_type_check_numeric(expr->expr);
|
||||
case JAF_BIT_NOT:
|
||||
case JAF_LOG_NOT:
|
||||
return jaf_type_check_int(expr->expr);
|
||||
case JAF_AMPERSAND:
|
||||
ERROR("Function types not supported");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ERROR("Unhandled unary operator");
|
||||
}
|
||||
|
||||
static enum jaf_type jaf_check_types_binary(struct jaf_expression *expr)
|
||||
{
|
||||
jaf_derive_types(expr->lhs);
|
||||
jaf_derive_types(expr->rhs);
|
||||
switch (expr->op) {
|
||||
// real ops
|
||||
case JAF_MULTIPLY:
|
||||
case JAF_DIVIDE:
|
||||
case JAF_PLUS:
|
||||
case JAF_MINUS:
|
||||
return jaf_merge_types(jaf_type_check_numeric(expr->lhs), jaf_type_check_numeric(expr->rhs));
|
||||
// integer ops
|
||||
case JAF_REMAINDER:
|
||||
case JAF_LSHIFT:
|
||||
case JAF_RSHIFT:
|
||||
case JAF_BIT_AND:
|
||||
case JAF_BIT_XOR:
|
||||
case JAF_BIT_IOR:
|
||||
jaf_type_check_int(expr->lhs);
|
||||
jaf_type_check_int(expr->rhs);
|
||||
return JAF_INT;
|
||||
// comparison ops
|
||||
case JAF_LT:
|
||||
case JAF_GT:
|
||||
case JAF_LTE:
|
||||
case JAF_GTE:
|
||||
case JAF_EQ:
|
||||
jaf_type_check_numeric(expr->lhs);
|
||||
jaf_type_check_numeric(expr->rhs);
|
||||
return JAF_INT;
|
||||
// boolean ops
|
||||
case JAF_LOG_AND:
|
||||
case JAF_LOG_OR:
|
||||
jaf_type_check_int(expr->lhs);
|
||||
jaf_type_check_int(expr->rhs);
|
||||
return JAF_INT;
|
||||
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 expressions not supported");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ERROR("Unhandled binary operator");
|
||||
}
|
||||
|
||||
static enum jaf_type jaf_check_types_ternary(struct jaf_expression *expr)
|
||||
{
|
||||
jaf_derive_types(expr->condition);
|
||||
jaf_derive_types(expr->consequent);
|
||||
jaf_derive_types(expr->alternative);
|
||||
|
||||
TYPE_CHECK(expr->condition, JAF_INT);
|
||||
if (expr->consequent->derived_type != expr->alternative->derived_type) {
|
||||
// TODO: better error message
|
||||
ERROR("Mismatched types in conditional expression");
|
||||
}
|
||||
|
||||
return expr->consequent->derived_type;
|
||||
}
|
||||
|
||||
static enum jaf_type _jaf_check_types(struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->type) {
|
||||
case JAF_EXP_INT:
|
||||
return JAF_INT;
|
||||
case JAF_EXP_FLOAT:
|
||||
return JAF_FLOAT;
|
||||
case JAF_EXP_STRING:
|
||||
return JAF_STRING;
|
||||
case JAF_EXP_IDENTIFIER:
|
||||
// TODO: need environment
|
||||
ERROR("Identifiers not supported");
|
||||
case JAF_EXP_UNARY:
|
||||
return jaf_check_types_unary(expr);
|
||||
case JAF_EXP_BINARY:
|
||||
return jaf_check_types_binary(expr);
|
||||
case JAF_EXP_TERNARY:
|
||||
return jaf_check_types_ternary(expr);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ERROR("Unhandled expression type");
|
||||
}
|
||||
|
||||
static void jaf_derive_types(struct jaf_expression *expr)
|
||||
{
|
||||
expr->derived_type = _jaf_check_types(expr);
|
||||
}
|
||||
|
||||
void jaf_check_types(struct jaf_expression *expr, struct jaf_type_specifier *type)
|
||||
{
|
||||
jaf_derive_types(expr);
|
||||
// TODO: struct types, etc.
|
||||
if (expr->derived_type != type->type) {
|
||||
TYPE_ERROR(expr, type->type);
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,18 @@ ainedit = ['../../cJSON.c',
|
||||
'../conv.c',
|
||||
'ainedit.c',
|
||||
'asm.c',
|
||||
'jaf_ast.c',
|
||||
'jaf_compile.c',
|
||||
'jaf_eval.c',
|
||||
'jaf_types.c',
|
||||
'json.c',
|
||||
'repack.c',
|
||||
'text.c',
|
||||
'transcode.c',
|
||||
]
|
||||
|
||||
ainedit += flexgen.process('asm_lexer.l', 'text_lexer.l')
|
||||
ainedit += bisongen.process('asm_parser.y', 'text_parser.y')
|
||||
ainedit += flexgen.process('asm_lexer.l', 'text_lexer.l', 'jaf_lexer.l')
|
||||
ainedit += bisongen.process('asm_parser.y', 'text_parser.y', 'jaf_parser.y')
|
||||
|
||||
executable('ainedit', ainedit,
|
||||
dependencies : tool_deps,
|
||||
|
||||
Reference in New Issue
Block a user