* Copyright (C) 2012, 2013
* Wolfgang Bumiller
* Dale Weiler
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
ast_value **imm_vector;
size_t translated;
+ ht ht_imm_string;
+
/* must be deleted first, they reference immediates and values */
ast_value **accessors;
/* collected information */
size_t max_param_count;
+
+ /* code generator */
+ code_t *code;
} parser_t;
static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT);
out->cvq = CV_CONST;
out->hasvalue = true;
+ out->isimm = true;
out->constval.vfloat = d;
vec_push(parser->imm_float, out);
return out;
static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate)
{
- size_t i;
+ size_t hash = util_hthash(parser->ht_imm_string, str);
ast_value *out;
+ if ( (out = (ast_value*)util_htgeth(parser->ht_imm_string, str, hash)) ) {
+ if (dotranslate && out->name[0] == '#') {
+ char name[32];
+ util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
+ ast_value_set_name(out, name);
+ }
+ return out;
+ }
+ /*
for (i = 0; i < vec_size(parser->imm_string); ++i) {
if (!strcmp(parser->imm_string[i]->constval.vstring, str))
return parser->imm_string[i];
}
+ */
if (dotranslate) {
char name[32];
- snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
+ util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
out = ast_value_new(parser_ctx(parser), name, TYPE_STRING);
} else
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
out->cvq = CV_CONST;
out->hasvalue = true;
+ out->isimm = true;
out->constval.vstring = parser_strdup(str);
vec_push(parser->imm_string, out);
+ util_htseth(parser->ht_imm_string, str, hash, out);
return out;
}
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR);
out->cvq = CV_CONST;
out->hasvalue = true;
+ out->isimm = true;
out->constval.vvec = v;
vec_push(parser->imm_vector, out);
return out;
return out;
}
+/* not to be exposed */
+extern bool ftepp_predef_exists(const char *name);
+
static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
{
if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
vec_push(parser->labels, lbl);
}
}
+ if (!var && !strcmp(parser_tokval(parser), "__FUNC__"))
+ var = (ast_expression*)parser_const_string(parser, parser->function->name, false);
if (!var) {
/* intrinsics */
if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
*/
else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) {
var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */);
- } else {
- var = intrin_func(parser, parser_tokval(parser));
}
-
+
if (!var) {
char *correct = NULL;
size_t i;
* i've done this thousands of times already myself. Lets check for
* it in the predef table. And diagnose it better :)
*/
- if (!OPTS_FLAG(FTEPP_PREDEFS)) {
- for (i = 0; i < sizeof(ftepp_predefs)/sizeof(*ftepp_predefs); i++) {
- if (!strcmp(ftepp_predefs[i].name, parser_tokval(parser))) {
- parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
- return false;
- }
- }
+ if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) {
+ parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
+ return false;
}
/*
wantop = true;
}
else {
- parseerror(parser, "expected operator or end of statement");
- goto onerr;
+ /* in this case we might want to allow constant string concatenation */
+ bool concatenated = false;
+ if (parser->tok == TOKEN_STRINGCONST && vec_size(sy.out)) {
+ ast_expression *lexpr = vec_last(sy.out).out;
+ if (ast_istype(lexpr, ast_value)) {
+ ast_value *last = (ast_value*)lexpr;
+ if (last->isimm == true && last->cvq == CV_CONST &&
+ last->hasvalue && last->expression.vtype == TYPE_STRING)
+ {
+ char *newstr = NULL;
+ util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser));
+ vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false);
+ mem_d(newstr);
+ concatenated = true;
+ }
+ }
+ }
+ if (!concatenated) {
+ parseerror(parser, "expected operator or end of statement");
+ goto onerr;
+ }
}
if (!parser_next(parser)) {
varargs->expression.flags |= AST_FLAG_IS_VARARG;
varargs->expression.next = (ast_expression*)ast_value_new(ast_ctx(var), NULL, TYPE_VECTOR);
varargs->expression.count = 0;
- snprintf(name, sizeof(name), "%s##va##SET", var->name);
+ util_snprintf(name, sizeof(name), "%s##va##SET", var->name);
if (!parser_create_array_setter_proto(parser, varargs, name)) {
ast_delete(varargs);
ast_block_delete(block);
goto enderrfn;
}
- snprintf(name, sizeof(name), "%s##va##GET", var->name);
+ util_snprintf(name, sizeof(name), "%s##va##GET", var->name);
if (!parser_create_array_getter_proto(parser, varargs, varargs->expression.next, name)) {
ast_delete(varargs);
ast_block_delete(block);
bool cleanvar = true;
bool wasarray = false;
- ast_member *me[3];
+ ast_member *me[3] = { NULL, NULL, NULL };
if (!localblock && is_static)
parseerror(parser, "`static` qualifier is not supported in global scope");
/*
* store the vstring back to var for alias and
* deprecation messages.
- */
+ */
if (var->expression.flags & AST_FLAG_DEPRECATED ||
var->expression.flags & AST_FLAG_ALIAS)
var->desc = vstring;
ast_value_set_name(proto->expression.params[i], var->expression.params[i]->name);
if (!parser_check_qualifiers(parser, var, proto)) {
retval = false;
- if (proto->desc)
+ if (proto->desc)
mem_d(proto->desc);
proto = NULL;
goto cleanup;
/*
* add alias to aliases table and to corrector
* so corrections can apply for aliases as well.
- */
+ */
util_htset(parser->aliases, var->name, find);
/*
* add to corrector so corrections can work
* even for aliases too.
- */
+ */
correct_add (
vec_last(parser->correct_variables),
&vec_last(parser->correct_variables_score),
/*
* add to corrector so corrections can work
* even for aliases too.
- */
+ */
correct_add (
vec_last(parser->correct_variables),
&vec_last(parser->correct_variables_score),
*/
if (var->expression.vtype == TYPE_ARRAY) {
char name[1024];
- snprintf(name, sizeof(name), "%s##SET", var->name);
+ util_snprintf(name, sizeof(name), "%s##SET", var->name);
if (!parser_create_array_setter(parser, var, name))
goto cleanup;
- snprintf(name, sizeof(name), "%s##GET", var->name);
+ util_snprintf(name, sizeof(name), "%s##GET", var->name);
if (!parser_create_array_getter(parser, var, var->expression.next, name))
goto cleanup;
}
goto cleanup;
}
- snprintf(name, sizeof(name), "%s##SETF", var->name);
+ util_snprintf(name, sizeof(name), "%s##SETF", var->name);
if (!parser_create_array_field_setter(parser, array, name))
goto cleanup;
telem = ast_type_copy(ast_ctx(var), array->expression.next);
tfield = ast_value_new(ast_ctx(var), "<.type>", TYPE_FIELD);
tfield->expression.next = telem;
- snprintf(name, sizeof(name), "%s##GETFP", var->name);
+ util_snprintf(name, sizeof(name), "%s##GETFP", var->name);
if (!parser_create_array_getter(parser, array, (ast_expression*)tfield, name)) {
ast_delete(tfield);
goto cleanup;
if (parser->tok == '#') {
ast_function *func = NULL;
+ ast_value *number;
+ int builtin_num;
if (localblock) {
parseerror(parser, "cannot declare builtins within functions");
parseerror(parser, "expected builtin number");
break;
}
- if (parser->tok != TOKEN_INTCONST) {
+
+ number = (ast_value*)parse_expression_leave(parser, true, false, false);
+ if (!number) {
+ parseerror(parser, "builtin number expected");
+ break;
+ }
+ if (!ast_istype(number, ast_value) || !number->hasvalue || number->cvq != CV_CONST)
+ {
+ ast_unref(number);
+ parseerror(parser, "builtin number must be a compile time constant");
+ break;
+ }
+ if (number->expression.vtype == TYPE_INTEGER)
+ builtin_num = number->constval.vint;
+ else if (number->expression.vtype == TYPE_FLOAT)
+ builtin_num = number->constval.vfloat;
+ else {
+ ast_unref(number);
parseerror(parser, "builtin number must be an integer constant");
break;
}
- if (parser_token(parser)->constval.i < 0) {
+ ast_unref(number);
+
+ if (builtin_num < 0) {
parseerror(parser, "builtin number must be an integer greater than zero");
break;
}
}
vec_push(parser->functions, func);
- func->builtin = -parser_token(parser)->constval.i-1;
+ func->builtin = -builtin_num-1;
}
- if (!parser_next(parser)) {
+ if (parser->tok != ',' && parser->tok != ';') {
parseerror(parser, "expected comma or semicolon");
if (func)
ast_function_delete(func);
}
crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
- code_crc = crc;
+ parser->code->crc = crc;
}
parser_t *parser_create()
memset(parser, 0, sizeof(*parser));
+ if (!(parser->code = code_init())) {
+ mem_d(parser);
+ return NULL;
+ }
+
+
for (i = 0; i < operator_count; ++i) {
if (operators[i].id == opid1('=')) {
parser->assign_op = operators+i;
parser->aliases = util_htnew(PARSER_HT_SIZE);
+ parser->ht_imm_string = util_htnew(512);
+
/* corrector */
vec_push(parser->correct_variables, correct_trie_new());
vec_push(parser->correct_variables_score, NULL);
vec_free(parser->functions);
vec_free(parser->imm_vector);
vec_free(parser->imm_string);
+ util_htdel(parser->ht_imm_string);
vec_free(parser->imm_float);
vec_free(parser->globals);
vec_free(parser->fields);
generate_checksum(parser);
- if (!ir_builder_generate(ir, output)) {
+ if (!ir_builder_generate(parser->code, ir, output)) {
con_out("*** failed to generate output file\n");
ir_builder_delete(ir);
return false;