[qfcc] Add declaration expressions

Now declarations can be deferred too, thus things like generic/template
and inline functions should be possible. However, the most important
thing is this is a step towards a cleaner middle layer for compilation,
separating front-end language from back-end code-gen.
This commit is contained in:
Bill Currie 2024-10-04 11:51:34 +09:00
parent 8b9333e108
commit d46620fcf4
12 changed files with 266 additions and 85 deletions

View file

@ -114,6 +114,7 @@ typedef struct ex_list_s {
typedef struct {
ex_list_t list;
symtab_t *scope;
const expr_t *result; ///< the result of this block if non-void
int is_call; ///< this block exprssion forms a function call
void *return_addr; ///< who allocated this
@ -342,6 +343,11 @@ typedef struct {
const type_t *type;
} ex_array_t;
typedef struct {
specifier_t spec;
ex_list_t list;
} ex_decl_t;
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
typedef struct expr_s {
@ -389,6 +395,7 @@ typedef struct expr_s {
ex_cond_t cond; ///< ?: conditional expression
ex_field_t field; ///< field reference expression
ex_array_t array; ///< array index expression
ex_decl_t decl; ///< variable declaration expression
};
} expr_t;
@ -460,6 +467,8 @@ expr_t *expr_prepend_list (expr_t *list, ex_list_t *prepend);
*/
expr_t *new_expr (void);
expr_t *new_error_expr (void);
/** Create a new label name.
The label name is guaranteed to be unique to the compilation. It is made
@ -902,6 +911,9 @@ expr_t *new_cond_expr (const expr_t *test, const expr_t *true_expr,
const expr_t *false_expr);
expr_t *new_field_expr (const expr_t *object, const expr_t *member);
expr_t *new_array_expr (const expr_t *base, const expr_t *index);
expr_t *new_decl_expr (specifier_t spec);
expr_t *append_decl (expr_t *decl, symbol_t *sym, const expr_t *init);
expr_t *append_decl_list (expr_t *decl, const expr_t *list);
/** Create an expression of the correct type that references the specified
parameter slot.

View file

@ -56,7 +56,7 @@ EX_EXPR(compound) ///< compound initializer
EX_EXPR(memset) ///< memset needs three params...
EX_EXPR(alias) ///< view expression as different type (::ex_alias_t)
EX_EXPR(address) ///< address of an lvalue expression (::ex_address_t)
EX_EXPR(assign) ///< assignment of src expr to dst expr (::ex_assing_t)
EX_EXPR(assign) ///< assignment of src expr to dst expr (::ex_assign_t)
EX_EXPR(branch) ///< branch expression (::ex_branch_t)
EX_EXPR(inout) ///< inout arg expression (::ex_inout_t)
EX_EXPR(return) ///< return expression (::ex_return_t)
@ -72,7 +72,8 @@ EX_EXPR(type) ///< type expression for generics
EX_EXPR(incop) ///< pre or post increment/decrement (::ex_incop_t)
EX_EXPR(cond) ///< ?: conditional expression (::ex_cond_t)
EX_EXPR(field) ///< field reference expression (::ex_field_t)
EX_EXPR(array) ///< array index ex_field_t (::ex_array_t)
EX_EXPR(array) ///< array index expression (::ex_array_t)
EX_EXPR(decl) ///< delcaration expression (::ex_array_t)
#undef EX_EXPR

View file

@ -98,8 +98,7 @@ glsl_block_t *glsl_get_block (const char *name, glsl_interface_t interface);
symtab_t *glsl_optimize_attributes (attribute_t *attributes);
void glsl_apply_attributes (symtab_t *attributes, specifier_t spec);
void glsl_parse_declaration (specifier_t spec,
symbol_t *sym, const type_t *array,
void glsl_parse_declaration (specifier_t spec, symbol_t *sym,
const expr_t *init, symtab_t *symtab);
void glsl_declare_field (specifier_t spec, symtab_t *symtab);
void glsl_layout (const ex_list_t *qualifiers, specifier_t spec);

View file

@ -68,6 +68,7 @@ typedef struct rua_loc_s {
} while (0)
typedef struct expr_s expr_t;
typedef struct symbol_s symbol_t;
typedef struct symtab_s symtab_t;
typedef struct function_s function_t;
@ -202,6 +203,8 @@ typedef struct language_s {
void (*extension) (const char *name, const char *value, void *scanner);
void (*version) (int version, const char *profile);
bool (*on_include) (const char *name);
void (*parse_declaration) (specifier_t spec, symbol_t *sym,
const expr_t *init, symtab_t *symtab);
void *sublanguage;
} language_t;

View file

@ -141,6 +141,7 @@ get_type (const expr_t *e)
case ex_error:
return 0;
case ex_return:
case ex_decl:
internal_error (e, "unexpected expression type");
case ex_label:
case ex_compound:
@ -461,7 +462,7 @@ new_label_name (void)
return lname;
}
static expr_t *
expr_t *
new_error_expr (void)
{
expr_t *e = new_expr ();
@ -1593,8 +1594,12 @@ new_type_expr (const type_t *type)
expr_t *
append_expr (expr_t *block, const expr_t *e)
{
if (block->type != ex_block)
if (block->type != ex_block) {
internal_error (block, "not a block expression");
}
if (e == block) {
internal_error (block, "adding block to itself");
}
if (!e || e->type == ex_error)
return block;
@ -1924,6 +1929,7 @@ has_function_call (const expr_t *e)
case ex_with:
case ex_args:
case ex_type:
case ex_decl:
return 0;
case ex_multivec:
for (auto c = e->multivec.components.head; c; c = c->next) {
@ -2523,6 +2529,38 @@ new_array_expr (const expr_t *base, const expr_t *index)
return array;
}
expr_t *
new_decl_expr (specifier_t spec)
{
auto decl = new_expr ();
decl->type = ex_decl;
decl->decl = (ex_decl_t) {
.spec = spec,
};
return decl;
}
expr_t *
append_decl (expr_t *decl, symbol_t *sym, const expr_t *init)
{
auto expr = new_symbol_expr (sym);
if (init) {
expr = new_assign_expr (expr, init);
}
list_append (&decl->decl.list, expr);
return decl;
}
expr_t *
append_decl_list (expr_t *decl, const expr_t *list)
{
if (list->type != ex_list) {
internal_error (list, "not a list expression");
}
list_append_list (&decl->decl.list, &list->list);
return decl;
}
const expr_t *
incop_expr (int op, const expr_t *e, int postop)
{

View file

@ -132,6 +132,7 @@ is_lvalue (const expr_t *expr)
case ex_list:
case ex_type:
case ex_incop:
case ex_decl:
break;
case ex_cond:
return (is_lvalue (expr->cond.true_expr)

View file

@ -74,6 +74,9 @@ math_constructor (const type_t *type, const expr_t *params, const expr_t *e)
if (p < num_param) {
auto pexpr = param_exprs[p++];
auto ptype = get_type (pexpr);
if (!ptype) {
continue;
}
if (!is_math (ptype)) {
components[c++] = error (pexpr, "invalid type for conversion");
continue;

View file

@ -79,6 +79,7 @@ edag_add_expr (const expr_t *expr)
case ex_args:
case ex_type:
case ex_incop:
case ex_decl:
// these are never put in the dag
return expr;
case ex_list:

View file

@ -37,6 +37,7 @@
#include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/expr.h"
#include "tools/qfcc/include/rua-lang.h"
#include "tools/qfcc/include/shared.h"
#include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/type.h"
#include "tools/qfcc/include/value.h"
@ -55,6 +56,7 @@ proc_expr (const expr_t *expr)
return e2;
}
scoped_src_loc (expr);
return binary_expr (expr->expr.op, e1, e2);
}
@ -66,34 +68,83 @@ proc_uexpr (const expr_t *expr)
return e1;
}
scoped_src_loc (expr);
return unary_expr (expr->expr.op, e1);
}
static const expr_t *
proc_block (const expr_t *expr)
{
if (expr->block.scope) {
expr->block.scope->parent = current_symtab;
current_symtab = expr->block.scope;
}
int count = list_count (&expr->block.list);
int num_out = 0;
const expr_t *result = nullptr;
const expr_t *in[count + 1];
const expr_t *out[count + 1];
list_scatter (&expr->block.list, in);
for (int i = 0; i < count; i++) {
auto e = expr_process (in[i]);
if (e && !is_error (e)) {
out[num_out++] = e;
if (expr->block.result == in[i]) {
result = e;
}
}
}
scoped_src_loc (expr);
auto block = new_block_expr (nullptr);
list_gather (&block->block.list, out, num_out);
block->block.scope = expr->block.scope;
block->block.result = result;
block->block.is_call = expr->block.is_call;
if (expr->block.scope) {
current_symtab = current_symtab->parent;
}
return block;
}
static const expr_t *
proc_symbol (const expr_t *expr)
{
auto sym = symtab_lookup (current_symtab, expr->symbol->name);
if (sym) {
scoped_src_loc (expr);
expr = new_symbol_expr (sym);
}
return expr;
}
static void
static bool
proc_do_list (ex_list_t *out, const ex_list_t *in)
{
int count = list_count (in);
const expr_t *exprs[count + 1];
list_scatter (in, exprs);
bool ok = true;
for (int i = 0; i < count; i++) {
exprs[i] = expr_process (exprs[i]);
if (is_error (exprs[i])) {
ok = false;
}
}
list_gather (out, exprs, count);
return ok;
}
static const expr_t *
proc_vector (const expr_t *expr)
{
scoped_src_loc (expr);
auto vec = new_expr ();
vec->type = ex_vector;
vec->vector.type = expr->vector.type;
proc_do_list (&vec->vector.list, &expr->vector.list);
if (!proc_do_list (&vec->vector.list, &expr->vector.list)) {
return new_error_expr ();
}
return vec;
}
@ -106,6 +157,7 @@ proc_value (const expr_t *expr)
static const expr_t *
proc_compound (const expr_t *expr)
{
scoped_src_loc (expr);
auto comp = new_compound_init ();
for (auto ele = expr->compound.head; ele; ele = ele->next) {
append_element (comp, new_element (expr_process (ele->expr),
@ -125,12 +177,14 @@ proc_assign (const expr_t *expr)
if (is_error (src)) {
return src;
}
scoped_src_loc (expr);
return assign_expr (dst, src);
}
static const expr_t *
proc_branch (const expr_t *expr)
{
scoped_src_loc (expr);
if (expr->branch.type == pr_branch_call) {
auto args = new_list_expr (nullptr);
proc_do_list (&args->list, &expr->branch.args->list);
@ -155,18 +209,58 @@ proc_branch (const expr_t *expr)
}
}
static const expr_t *
proc_decl (const expr_t *expr)
{
if (expr->decl.spec.storage == sc_local) {
scoped_src_loc (expr);
local_expr = new_block_expr (nullptr);
}
int count = list_count (&expr->decl.list);
const expr_t *decls[count + 1];
list_scatter (&expr->decl.list, decls);
for (int i = 0; i < count; i++) {
auto decl = decls[i];
const expr_t *init = nullptr;
symbol_t *sym;
if (decl->type == ex_assign) {
init = decl->assign.src;
if (decl->assign.dst->type != ex_symbol) {
internal_error (decl->assign.dst, "not a symbol");
}
sym = decl->assign.dst->symbol;
} else if (decl->type == ex_symbol) {
sym = decl->symbol;
} else {
internal_error (decl->assign.dst, "not a symbol");
}
auto spec = expr->decl.spec;
if (sym && sym->type) {
spec.type = append_type (sym->type, spec.type);
spec.type = find_type (spec.type);
sym->type = nullptr;
}
current_language.parse_declaration (spec, sym, init, current_symtab);
}
auto block = local_expr;
local_expr = nullptr;
return block;
}
const expr_t *
expr_process (const expr_t *expr)
{
static process_f funcs[ex_count] = {
[ex_expr] = proc_expr,
[ex_uexpr] = proc_uexpr,
[ex_block] = proc_block,
[ex_symbol] = proc_symbol,
[ex_vector] = proc_vector,
[ex_value] = proc_value,
[ex_compound] = proc_compound,
[ex_assign] = proc_assign,
[ex_branch] = proc_branch,
[ex_decl] = proc_decl,
};
if (expr->type >= ex_count) {

View file

@ -42,18 +42,17 @@
#include "tools/qfcc/include/type.h"
void
glsl_parse_declaration (specifier_t spec, symbol_t *sym, const type_t *array,
glsl_parse_declaration (specifier_t spec, symbol_t *sym,
const expr_t *init, symtab_t *symtab)
{
if (sym->type) {
internal_error (0, "unexected typed symbol");
}
if (array) {
spec.type = append_type (array, spec.type);
spec.type = find_type (spec.type);
}
if (init) {
init = expr_process (init);
if (is_error (init)) {
return;
}
}
auto attributes = glsl_optimize_attributes (spec.attributes);
if (sym && sym->sy_type == sy_expr) {

View file

@ -168,7 +168,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%type <symbol> variable_identifier
%type <block> block_declaration
%type <expr> constant_expression
%type <expr> declaration constant_expression
%type <expr> expression primary_exprsssion assignment_expression
%type <expr> for_init_statement conditionopt expressionopt else
%type <expr> conditional_expression unary_expression postfix_expression
@ -186,6 +186,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%type <expr> condition
%type <expr> compound_statement_no_new_scope compound_statement
%type <expr> statement statement_no_new_scope statement_list
%type <expr> new_block new_scope
%type <expr> simple_statement expression_statement
%type <expr> declaration_statement selection_statement
%type <expr> switch_statement switch_statement_list case_label
@ -193,9 +194,9 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc);
%type <expr> iteration_statement jump_statement
%type <expr> break_label continue_label
%type <mut_expr> initializer_list
%type <mut_expr> single_declaration init_declarator_list
%type <op> unary_operator assignment_operator
%type <spec> single_declaration init_declarator_list
%type <spec> function_prototype function_declarator
%type <spec> function_header function_header_with_parameters
%type <spec> fully_specified_type type_specifier struct_specifier
@ -269,7 +270,7 @@ translation_unit
external_declaration
: function_definition
| declaration
| declaration { if ($1) expr_process ($1); }
| ';'
;
@ -290,7 +291,8 @@ function_definition
{
auto spec = $1;
auto sym = spec.sym;
build_code_function (sym, nullptr, (expr_t *) $3);
expr_t *statments = (expr_t *) expr_process ($3);
build_code_function (sym, nullptr, statments);
current_symtab = $<symtab>2;
current_storage = sc_global;//FIXME
current_func = nullptr;
@ -569,50 +571,62 @@ constant_expression
;
declaration
: function_prototype ';'
| init_declarator_list ';'
: function_prototype ';' { $$ = nullptr; }
| init_declarator_list ';' { $$ = $1; }
| PRECISION precision_qualifier type_specifier ';'
{
notice (0, "PRECISION precision_qualifier");
$$ = nullptr;
}
| type_qualifier block_declaration ';'
{
auto block = $block_declaration;
glsl_declare_block_instance (block, nullptr);
if (current_symtab != pr.symtab) {
error (0, "blocks must be declared globally");
} else {
auto block = $block_declaration;
glsl_declare_block_instance (block, nullptr);
}
$$ = nullptr;
}
| type_qualifier block_declaration IDENTIFIER ';'
{
auto block = $block_declaration;
auto instance_name = $IDENTIFIER;
glsl_declare_block_instance (block, instance_name);
if (current_symtab != pr.symtab) {
error (0, "blocks must be declared globally");
} else {
auto block = $block_declaration;
auto instance_name = $IDENTIFIER;
glsl_declare_block_instance (block, instance_name);
}
$$ = nullptr;
}
| type_qualifier block_declaration IDENTIFIER array_specifier ';'
{
auto block = $block_declaration;
auto instance_name = $IDENTIFIER;
instance_name->type = $array_specifier;
glsl_declare_block_instance (block, instance_name);
if (current_symtab != pr.symtab) {
error (0, "blocks must be declared globally");
} else {
auto block = $block_declaration;
auto instance_name = $IDENTIFIER;
instance_name->type = $array_specifier;
glsl_declare_block_instance (block, instance_name);
}
$$ = nullptr;
}
| type_qualifier ';'
{
glsl_parse_declaration ($type_qualifier, nullptr,
nullptr, nullptr, current_symtab);
nullptr, current_symtab);
$$ = nullptr;
}
| type_qualifier IDENTIFIER ';'
{
glsl_parse_declaration ($type_qualifier, $IDENTIFIER,
nullptr, nullptr, current_symtab);
auto decl = new_decl_expr ($type_qualifier);
$$ = append_decl (decl, $IDENTIFIER, nullptr);
}
| type_qualifier IDENTIFIER identifier_list ';'
{
auto id_list = $identifier_list;
auto expr = new_symbol_expr ($IDENTIFIER);
expr_prepend_expr (id_list, expr);
auto sym = new_symbol (nullptr);
sym->sy_type = sy_expr;
sym->expr = id_list;
glsl_parse_declaration ($type_qualifier, sym,
nullptr, nullptr, current_symtab);
auto decl = new_decl_expr ($type_qualifier);
append_decl (decl, $IDENTIFIER, nullptr);
$$ = append_decl_list (decl, $identifier_list);
}
;
@ -723,60 +737,58 @@ init_declarator_list
: single_declaration
| init_declarator_list ',' IDENTIFIER
{
$$ = $1;
auto symtab = current_symtab;
auto space = symtab->space;
auto storage = current_storage;
initialize_def ($3, nullptr, space, storage, symtab);
auto decl = $1;
$$ = append_decl (decl, $IDENTIFIER, nullptr);
}
| init_declarator_list ',' IDENTIFIER array_specifier
{
auto decl = $1;
$IDENTIFIER->type = $array_specifier;
$$ = append_decl (decl, $IDENTIFIER, nullptr);
}
| init_declarator_list ',' IDENTIFIER array_specifier '=' initializer
{
auto decl = $1;
$IDENTIFIER->type = $array_specifier;
$$ = append_decl (decl, $IDENTIFIER, $initializer);
}
| init_declarator_list ',' IDENTIFIER '=' initializer
{
$$ = $1;
auto symtab = current_symtab;
auto space = symtab->space;
auto storage = current_storage;
if (storage == sc_local && !local_expr) {
local_expr = new_block_expr (nullptr);
}
initialize_def ($3, $5, space, storage, symtab);
auto decl = $1;
$$ = append_decl (decl, $IDENTIFIER, $initializer);
}
;
single_declaration
: fully_specified_type
{
glsl_parse_declaration ($$ = $fully_specified_type,
nullptr, nullptr,
nullptr, current_symtab);
$$ = new_decl_expr ($fully_specified_type);
}
| fully_specified_type IDENTIFIER
{
glsl_parse_declaration ($$ = $fully_specified_type,
$IDENTIFIER, nullptr,
nullptr, current_symtab);
auto decl = new_decl_expr ($fully_specified_type);
$$ = append_decl (decl, $IDENTIFIER, nullptr);
}
| fully_specified_type IDENTIFIER array_specifier
{
glsl_parse_declaration ($$ = $fully_specified_type,
$IDENTIFIER, $array_specifier,
nullptr, current_symtab);
auto spec = $fully_specified_type;
spec.type = append_type ($array_specifier, spec.type);
spec.type = find_type (spec.type);
auto decl = new_decl_expr (spec);
$$ = append_decl (decl, $IDENTIFIER, nullptr);
}
| fully_specified_type IDENTIFIER array_specifier '=' initializer
{
glsl_parse_declaration ($$ = $fully_specified_type,
$IDENTIFIER, $array_specifier,
$initializer, current_symtab);
auto spec = $fully_specified_type;
spec.type = append_type ($array_specifier, spec.type);
spec.type = find_type (spec.type);
auto decl = new_decl_expr (spec);
$$ = append_decl (decl, $IDENTIFIER, $initializer);
}
| fully_specified_type IDENTIFIER '=' initializer
{
if (current_storage == sc_local && !local_expr) {
local_expr = new_block_expr (nullptr);
}
glsl_parse_declaration ($$ = $fully_specified_type,
$IDENTIFIER, nullptr,
$initializer, current_symtab);
auto decl = new_decl_expr ($fully_specified_type);
$$ = append_decl (decl, $IDENTIFIER, $initializer);
}
;
@ -1028,10 +1040,6 @@ initializer_list
declaration_statement
: declaration
{
$$ = local_expr;
local_expr = nullptr;
}
;
statement
@ -1041,7 +1049,7 @@ statement
simple_statement
: declaration_statement
| expression_statement { $$ = expr_process ($1); }//FIXME shouldn't be here
| expression_statement
| selection_statement
| switch_statement
| case_label
@ -1051,7 +1059,11 @@ simple_statement
compound_statement
: '{' '}' { $$ = nullptr; }
| '{' statement_list '}' { $$ = $2; }
| '{' new_scope statement_list '}'
{
$$ = $3;
current_symtab = $2->block.scope->parent;
}
;
statement_no_new_scope
@ -1061,13 +1073,31 @@ statement_no_new_scope
compound_statement_no_new_scope
: '{' '}' { $$ = nullptr; }
| '{' statement_list '}' { $$ = $2; }
| '{' new_block statement_list '}' { $$ = $3; }
;
new_scope
: /* empty */
{
auto block = new_block_expr (nullptr);
block->block.scope = new_symtab (nullptr, stab_local);
current_symtab = block->block.scope;
$$ = block;
}
;
new_block
: /* empty */
{
auto block = new_block_expr (nullptr);
$$ = block;
}
;
statement_list
: statement
{
auto list = new_block_expr (nullptr);
auto list = $<mut_expr>0;
append_expr (list, $1);
$$ = list;
}
@ -1160,7 +1190,7 @@ switch_block
switch_statement_list
: /* empty */ { $$ = nullptr; }
| statement_list
| new_block statement_list { $$ = $2; }
;
case_label
@ -1713,6 +1743,7 @@ language_t lang_glsl_comp = {
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
.parse_declaration = glsl_parse_declaration,
.sublanguage = &glsl_comp_sublanguage,
};
@ -1722,6 +1753,7 @@ language_t lang_glsl_vert = {
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
.parse_declaration = glsl_parse_declaration,
.sublanguage = &glsl_vert_sublanguage,
};
@ -1731,6 +1763,7 @@ language_t lang_glsl_tesc = {
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
.parse_declaration = glsl_parse_declaration,
.sublanguage = &glsl_tesc_sublanguage,
};
@ -1740,6 +1773,7 @@ language_t lang_glsl_tese = {
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
.parse_declaration = glsl_parse_declaration,
.sublanguage = &glsl_tese_sublanguage,
};
@ -1749,6 +1783,7 @@ language_t lang_glsl_geom = {
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
.parse_declaration = glsl_parse_declaration,
.sublanguage = &glsl_geom_sublanguage,
};
@ -1758,5 +1793,6 @@ language_t lang_glsl_frag = {
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
.parse_declaration = glsl_parse_declaration,
.sublanguage = &glsl_frag_sublanguage,
};

View file

@ -796,12 +796,6 @@ spirv_write (struct pr_info_s *pr, const char *filename)
spirv_MemoryModel (expr_uint (pr->module->addressing_model),
expr_uint (pr->module->memory_model), ctx.space);
for (auto sym = pr->symtab->symbols; sym; sym = sym->next) {
if (sym->sy_type == sy_expr && is_constexpr (sym->expr)) {
puts (sym->name);
spirv_emit_expr (sym->expr, &ctx);
}
}
auto srcid = spirv_String (pr->src_name, &ctx);
spirv_Source (0, 1, srcid, nullptr, &ctx);