mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-03 12:28:01 +03:00
jaf: support cast expressions
Support both function-style casts (eg. "int(12.3)") and C-style casts (eg. "(int)12.3").
This commit is contained in:
+14
-2
@@ -47,6 +47,10 @@ enum jaf_expression_type {
|
||||
JAF_EXP_UNARY,
|
||||
JAF_EXP_BINARY,
|
||||
JAF_EXP_TERNARY,
|
||||
//JAF_EXP_SUBSCRIPT,
|
||||
//JAF_EXP_FUNCALL,
|
||||
JAF_EXP_CAST,
|
||||
//JAF_EXP_MEMBER,
|
||||
};
|
||||
|
||||
enum jaf_operator {
|
||||
@@ -113,6 +117,11 @@ struct jaf_expression {
|
||||
struct jaf_expression *consequent;
|
||||
struct jaf_expression *alternative;
|
||||
};
|
||||
// cast
|
||||
struct {
|
||||
enum jaf_type type;
|
||||
struct jaf_expression *expr;
|
||||
} cast;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -221,14 +230,17 @@ struct jaf_block {
|
||||
struct jaf_block_item **items;
|
||||
};
|
||||
|
||||
struct jaf_expression *jaf_integer(struct string *text);
|
||||
struct jaf_expression *jaf_float(struct string *text);
|
||||
struct jaf_expression *jaf_integer(int i);
|
||||
struct jaf_expression *jaf_parse_integer(struct string *text);
|
||||
struct jaf_expression *jaf_float(float f);
|
||||
struct jaf_expression *jaf_parse_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_expression *jaf_cast_expression(enum jaf_type type, struct jaf_expression *expr);
|
||||
|
||||
struct jaf_type_specifier *jaf_type(enum jaf_type type);
|
||||
struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_block *fields);
|
||||
|
||||
+52
-14
@@ -30,33 +30,48 @@ static struct jaf_expression *jaf_expr(enum jaf_expression_type type, enum jaf_o
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_integer(struct string *text)
|
||||
struct jaf_expression *jaf_integer(int i)
|
||||
{
|
||||
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);
|
||||
e->derived_type = JAF_INT;
|
||||
e->i = i;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_float(struct string *text)
|
||||
struct jaf_expression *jaf_parse_integer(struct string *text)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_FLOAT, 0);
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
e->f = strtof(text->text, &endptr);
|
||||
int i = strtol(text->text, &endptr, 0);
|
||||
if (errno || *endptr != '\0')
|
||||
ERROR("Invalid integer constant");
|
||||
free_string(text);
|
||||
return jaf_integer(i);
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_float(float f)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_FLOAT, 0);
|
||||
e->derived_type = JAF_FLOAT;
|
||||
e->f = f;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_parse_float(struct string *text)
|
||||
{
|
||||
char *endptr;
|
||||
errno = 0;
|
||||
float f = strtof(text->text, &endptr);
|
||||
if (errno || *endptr != '\0')
|
||||
ERROR("Invalid floating point constant");
|
||||
free_string(text);
|
||||
return e;
|
||||
return jaf_float(f);
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_string(struct string *text)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_STRING, 0);
|
||||
e->derived_type = JAF_STRING;
|
||||
e->s = text;
|
||||
return e;
|
||||
}
|
||||
@@ -97,6 +112,14 @@ struct jaf_expression *jaf_seq_expr(struct jaf_expression *head, struct jaf_expr
|
||||
ERROR("Sequence expressions not supported");
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_cast_expression(enum jaf_type type, struct jaf_expression *expr)
|
||||
{
|
||||
struct jaf_expression *e = jaf_expr(JAF_EXP_CAST, 0);
|
||||
e->cast.type = type;
|
||||
e->cast.expr = expr;
|
||||
return e;
|
||||
}
|
||||
|
||||
struct jaf_type_specifier *jaf_type(enum jaf_type type)
|
||||
{
|
||||
struct jaf_type_specifier *p = xcalloc(1, sizeof(struct jaf_type_specifier));
|
||||
@@ -343,15 +366,30 @@ void jaf_free_expr(struct jaf_expression *expr)
|
||||
{
|
||||
if (!expr)
|
||||
return;
|
||||
if (expr->type == JAF_EXP_UNARY) {
|
||||
switch (expr->type) {
|
||||
case JAF_EXP_VOID:
|
||||
case JAF_EXP_INT:
|
||||
case JAF_EXP_FLOAT:
|
||||
break;
|
||||
case JAF_EXP_STRING:
|
||||
case JAF_EXP_IDENTIFIER:
|
||||
free_string(expr->s);
|
||||
break;
|
||||
case JAF_EXP_UNARY:
|
||||
jaf_free_expr(expr->expr);
|
||||
} else if (expr->type == JAF_EXP_BINARY) {
|
||||
break;
|
||||
case JAF_EXP_BINARY:
|
||||
jaf_free_expr(expr->lhs);
|
||||
jaf_free_expr(expr->rhs);
|
||||
} else if (expr->type == JAF_EXP_TERNARY) {
|
||||
break;
|
||||
case JAF_EXP_TERNARY:
|
||||
jaf_free_expr(expr->condition);
|
||||
jaf_free_expr(expr->consequent);
|
||||
jaf_free_expr(expr->alternative);
|
||||
break;
|
||||
case JAF_EXP_CAST:
|
||||
jaf_free_expr(expr->cast.expr);
|
||||
break;
|
||||
}
|
||||
free(expr);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "system4.h"
|
||||
#include "system4/string.h"
|
||||
#include "jaf.h"
|
||||
@@ -220,6 +221,70 @@ struct jaf_expression *jaf_simplify_ternary(struct jaf_expression *in)
|
||||
return in;
|
||||
}
|
||||
|
||||
struct jaf_expression *jaf_simplify_cast(struct jaf_expression *in)
|
||||
{
|
||||
in->cast.expr = jaf_simplify(in->cast.expr);
|
||||
|
||||
if (in->cast.type == JAF_INT) {
|
||||
if (in->cast.expr->type == JAF_EXP_INT) {
|
||||
struct jaf_expression *r = in->cast.expr;
|
||||
free(in);
|
||||
return r;
|
||||
}
|
||||
if (in->cast.expr->type == JAF_EXP_FLOAT) {
|
||||
struct jaf_expression *r = jaf_integer((int)in->cast.expr->f);
|
||||
jaf_free_expr(in);
|
||||
return r;
|
||||
}
|
||||
if (in->cast.expr->type == JAF_EXP_STRING) {
|
||||
struct jaf_expression *r = jaf_parse_integer(string_dup(in->cast.expr->s));
|
||||
jaf_free_expr(in);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (in->cast.type == JAF_FLOAT) {
|
||||
if (in->cast.expr->type == JAF_EXP_FLOAT) {
|
||||
struct jaf_expression *r = in->cast.expr;
|
||||
free(in);
|
||||
return r;
|
||||
}
|
||||
if (in->cast.expr->type == JAF_EXP_INT) {
|
||||
struct jaf_expression *r = jaf_float((float)in->cast.expr->i);
|
||||
jaf_free_expr(in);
|
||||
return r;
|
||||
}
|
||||
if (in->cast.expr->type == JAF_EXP_STRING) {
|
||||
struct jaf_expression *r = jaf_parse_float(string_dup(in->cast.expr->s));
|
||||
jaf_free_expr(in);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (in->cast.type == JAF_STRING) {
|
||||
if (in->cast.expr->type == JAF_EXP_STRING) {
|
||||
struct jaf_expression *r = in->cast.expr;
|
||||
free(in);
|
||||
return r;
|
||||
}
|
||||
if (in->cast.expr->type == JAF_EXP_INT) {
|
||||
char buf[512];
|
||||
snprintf(buf, 512, "%i", in->cast.expr->i);
|
||||
WARNING("CAST %d to string: %s", in->cast.expr->i, buf);
|
||||
jaf_free_expr(in);
|
||||
return jaf_string(make_string(buf, strlen(buf)));
|
||||
}
|
||||
if (in->cast.expr->type == JAF_EXP_FLOAT) {
|
||||
char buf[512];
|
||||
snprintf(buf, 512, "%f", in->cast.expr->f);
|
||||
jaf_free_expr(in);
|
||||
return jaf_string(make_string(buf, strlen(buf)));
|
||||
}
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simplify an expression by evaluating the constant parts.
|
||||
*/
|
||||
@@ -238,6 +303,8 @@ struct jaf_expression *jaf_simplify(struct jaf_expression *in)
|
||||
return jaf_simplify_binary(in);
|
||||
case JAF_EXP_TERNARY:
|
||||
return jaf_simplify_ternary(in);
|
||||
case JAF_EXP_CAST:
|
||||
return jaf_simplify_cast(in);
|
||||
}
|
||||
ERROR("Invalid expression type");
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ void yyerror(const char *s);
|
||||
|
||||
%token CASE DEFAULT IF ELSE SYM_SWITCH WHILE DO FOR GOTO CONTINUE BREAK SYM_RETURN
|
||||
|
||||
%type <token> unary_operator assignment_operator type_qualifier
|
||||
%type <token> unary_operator assignment_operator type_qualifier atomic_type_specifier
|
||||
%type <string> string param_identifer
|
||||
%type <expression> initializer
|
||||
%type <expression> postfix_expression unary_expression cast_expression
|
||||
@@ -89,8 +89,8 @@ primary_expression
|
||||
;
|
||||
|
||||
constant
|
||||
: I_CONSTANT { $$ = jaf_integer($1); } /* includes character_constant */
|
||||
| F_CONSTANT { $$ = jaf_float($1); }
|
||||
: I_CONSTANT { $$ = jaf_parse_integer($1); } /* includes character_constant */
|
||||
| F_CONSTANT { $$ = jaf_parse_float($1); }
|
||||
| ENUMERATION_CONSTANT { ERROR("Enums not supported"); } /* after it has been defined as such */
|
||||
;
|
||||
|
||||
@@ -108,7 +108,7 @@ 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"); }
|
||||
| atomic_type_specifier '(' expression ')' { $$ = jaf_cast_expression($1, $3); }
|
||||
| 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); }
|
||||
@@ -138,8 +138,8 @@ unary_operator
|
||||
;
|
||||
|
||||
cast_expression
|
||||
: unary_expression { $$ = $1; }
|
||||
| '(' type_specifier ')' cast_expression { ERROR("Cast not supported"); }
|
||||
: unary_expression { $$ = $1; }
|
||||
| '(' atomic_type_specifier ')' cast_expression { $$ = jaf_cast_expression($2, $4); }
|
||||
;
|
||||
|
||||
multiplicative_expression
|
||||
@@ -254,17 +254,21 @@ init_declarator
|
||||
| declarator { $$ = $1; }
|
||||
;
|
||||
|
||||
atomic_type_specifier
|
||||
: VOID { $$ = JAF_VOID; }
|
||||
| CHAR { $$ = JAF_INT; }
|
||||
| INT { $$ = JAF_INT; }
|
||||
| LONG { $$ = JAF_INT; }
|
||||
| FLOAT { $$ = JAF_FLOAT; }
|
||||
| BOOL { $$ = JAF_INT; }
|
||||
| STRING { $$ = JAF_STRING; }
|
||||
;
|
||||
|
||||
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 */
|
||||
: atomic_type_specifier { $$ = jaf_type($1); }
|
||||
| struct_specifier { $$ = $1; }
|
||||
| enum_specifier { ERROR("Enums not supported"); }
|
||||
| TYPEDEF_NAME { $$ = jaf_typedef($1); }
|
||||
;
|
||||
|
||||
struct_specifier
|
||||
|
||||
@@ -19,10 +19,24 @@
|
||||
#include "jaf.h"
|
||||
|
||||
// TODO: better error messages
|
||||
#define TYPE_ERROR(expr, expected) ERROR("Type error")
|
||||
#define TYPE_ERROR(expr, expected) ERROR("Type error (expected %s; got %s)", jaf_typestr(expected), jaf_typestr(expr->derived_type))
|
||||
#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 const char *jaf_typestr(enum jaf_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case JAF_VOID: return "void";
|
||||
case JAF_INT: return "int";
|
||||
case JAF_FLOAT: return "float";
|
||||
case JAF_STRING: return "string";
|
||||
case JAF_STRUCT: return "struct";
|
||||
case JAF_ENUM: return "enum";
|
||||
case JAF_TYPEDEF: return "typedef";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static enum jaf_type jaf_type_check_numeric(struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->derived_type != JAF_INT && expr->derived_type != JAF_FLOAT)
|
||||
@@ -143,6 +157,8 @@ static enum jaf_type jaf_check_types_ternary(struct jaf_expression *expr)
|
||||
static enum jaf_type _jaf_check_types(struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->type) {
|
||||
case JAF_EXP_VOID:
|
||||
return JAF_VOID;
|
||||
case JAF_EXP_INT:
|
||||
return JAF_INT;
|
||||
case JAF_EXP_FLOAT:
|
||||
@@ -158,8 +174,8 @@ static enum jaf_type _jaf_check_types(struct jaf_expression *expr)
|
||||
return jaf_check_types_binary(expr);
|
||||
case JAF_EXP_TERNARY:
|
||||
return jaf_check_types_ternary(expr);
|
||||
default:
|
||||
break;
|
||||
case JAF_EXP_CAST:
|
||||
return expr->cast.type;
|
||||
}
|
||||
ERROR("Unhandled expression type");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user