2001-09-28 07:09:38 +00:00
|
|
|
|
/*
|
2002-10-22 14:53:18 +00:00
|
|
|
|
expr.c
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
|
expression construction and manipulations
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
|
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
|
Date: 2001/06/15
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
|
|
|
|
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, write to:
|
|
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
|
|
*/
|
2002-06-01 04:41:25 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
|
2002-06-01 04:41:25 +00:00
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
|
# include <string.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
|
# include <strings.h>
|
|
|
|
|
#endif
|
2001-06-15 19:38:43 +00:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
2012-12-06 11:52:53 +00:00
|
|
|
|
#include "QF/alloc.h"
|
|
|
|
|
#include "QF/dstring.h"
|
|
|
|
|
#include "QF/mathlib.h"
|
|
|
|
|
#include "QF/va.h"
|
2001-06-20 21:18:04 +00:00
|
|
|
|
|
2020-06-21 14:15:17 +00:00
|
|
|
|
#include "tools/qfcc/include/qfcc.h"
|
|
|
|
|
#include "tools/qfcc/include/class.h"
|
|
|
|
|
#include "tools/qfcc/include/def.h"
|
|
|
|
|
#include "tools/qfcc/include/defspace.h"
|
|
|
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
|
|
|
#include "tools/qfcc/include/emit.h"
|
|
|
|
|
#include "tools/qfcc/include/expr.h"
|
|
|
|
|
#include "tools/qfcc/include/function.h"
|
|
|
|
|
#include "tools/qfcc/include/idstuff.h"
|
|
|
|
|
#include "tools/qfcc/include/method.h"
|
|
|
|
|
#include "tools/qfcc/include/options.h"
|
|
|
|
|
#include "tools/qfcc/include/reloc.h"
|
|
|
|
|
#include "tools/qfcc/include/shared.h"
|
|
|
|
|
#include "tools/qfcc/include/strpool.h"
|
|
|
|
|
#include "tools/qfcc/include/struct.h"
|
|
|
|
|
#include "tools/qfcc/include/symtab.h"
|
|
|
|
|
#include "tools/qfcc/include/type.h"
|
|
|
|
|
#include "tools/qfcc/include/value.h"
|
|
|
|
|
|
|
|
|
|
#include "tools/qfcc/source/qc-parse.h"
|
2001-06-20 21:18:04 +00:00
|
|
|
|
|
2023-03-05 07:26:37 +00:00
|
|
|
|
ALLOC_STATE (expr_t, exprs);
|
2001-12-06 19:49:40 +00:00
|
|
|
|
|
2011-02-05 13:32:23 +00:00
|
|
|
|
void
|
|
|
|
|
convert_name (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
symbol_t *sym;
|
|
|
|
|
expr_t *new;
|
|
|
|
|
|
|
|
|
|
if (e->type != ex_symbol)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
sym = e->e.symbol;
|
|
|
|
|
|
|
|
|
|
if (!strcmp (sym->name, "__PRETTY_FUNCTION__")
|
|
|
|
|
&& current_func) {
|
|
|
|
|
new = new_string_expr (current_func->name);
|
|
|
|
|
goto convert;
|
|
|
|
|
}
|
|
|
|
|
if (!strcmp (sym->name, "__FUNCTION__")
|
|
|
|
|
&& current_func) {
|
|
|
|
|
new = new_string_expr (current_func->def->name);
|
|
|
|
|
goto convert;
|
|
|
|
|
}
|
|
|
|
|
if (!strcmp (sym->name, "__LINE__")
|
|
|
|
|
&& current_func) {
|
2022-01-18 04:21:06 +00:00
|
|
|
|
new = new_int_expr (e->line);
|
2011-02-05 13:32:23 +00:00
|
|
|
|
goto convert;
|
|
|
|
|
}
|
2011-12-14 17:20:10 +00:00
|
|
|
|
if (!strcmp (sym->name, "__INFINITY__")
|
|
|
|
|
&& current_func) {
|
|
|
|
|
new = new_float_expr (INFINITY);
|
|
|
|
|
goto convert;
|
|
|
|
|
}
|
2011-02-05 13:32:23 +00:00
|
|
|
|
if (!strcmp (sym->name, "__FILE__")
|
|
|
|
|
&& current_func) {
|
|
|
|
|
new = new_string_expr (GETSTR (e->file));
|
|
|
|
|
goto convert;
|
|
|
|
|
}
|
|
|
|
|
if (!sym->table) {
|
|
|
|
|
error (e, "%s undefined", sym->name);
|
|
|
|
|
sym->type = type_default;
|
|
|
|
|
//FIXME need a def
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-05 09:45:47 +00:00
|
|
|
|
if (sym->sy_type == sy_convert) {
|
|
|
|
|
new = sym->s.convert.conv (sym, sym->s.convert.data);
|
|
|
|
|
goto convert;
|
|
|
|
|
}
|
2011-02-05 13:32:23 +00:00
|
|
|
|
if (sym->sy_type == sy_expr) {
|
2011-02-10 05:43:49 +00:00
|
|
|
|
new = copy_expr (sym->s.expr);
|
2011-02-05 13:32:23 +00:00
|
|
|
|
goto convert;
|
|
|
|
|
}
|
|
|
|
|
if (sym->sy_type == sy_type)
|
|
|
|
|
internal_error (e, "unexpected typedef");
|
|
|
|
|
// var, const and func shouldn't need extra handling
|
|
|
|
|
return;
|
|
|
|
|
convert:
|
|
|
|
|
e->type = new->type;
|
|
|
|
|
e->e = new->e;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-02 18:55:52 +00:00
|
|
|
|
type_t *
|
2001-06-20 07:02:36 +00:00
|
|
|
|
get_type (expr_t *e)
|
|
|
|
|
{
|
2020-03-28 03:10:23 +00:00
|
|
|
|
const type_t *type = 0;
|
2011-02-05 13:32:23 +00:00
|
|
|
|
convert_name (e);
|
2001-06-20 07:02:36 +00:00
|
|
|
|
switch (e->type) {
|
2022-01-09 05:02:16 +00:00
|
|
|
|
case ex_branch:
|
|
|
|
|
type = e->e.branch.ret_type;
|
|
|
|
|
break;
|
2022-01-21 04:09:23 +00:00
|
|
|
|
case ex_labelref:
|
2022-01-21 09:47:12 +00:00
|
|
|
|
case ex_adjstk:
|
|
|
|
|
case ex_with:
|
2022-01-21 04:09:23 +00:00
|
|
|
|
return &type_void;
|
2020-03-12 10:30:54 +00:00
|
|
|
|
case ex_memset:
|
|
|
|
|
return e->e.memset.type;
|
2002-05-01 22:08:59 +00:00
|
|
|
|
case ex_error:
|
2022-01-18 05:36:06 +00:00
|
|
|
|
return 0;
|
2022-01-09 07:28:08 +00:00
|
|
|
|
case ex_return:
|
|
|
|
|
internal_error (e, "unexpected expression type");
|
|
|
|
|
case ex_label:
|
2020-03-11 06:46:57 +00:00
|
|
|
|
case ex_compound:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
return 0;
|
2003-10-22 08:05:17 +00:00
|
|
|
|
case ex_bool:
|
|
|
|
|
if (options.code.progsversion == PROG_ID_VERSION)
|
|
|
|
|
return &type_float;
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return &type_int;
|
2001-10-17 07:45:37 +00:00
|
|
|
|
case ex_nil:
|
2020-03-13 08:57:58 +00:00
|
|
|
|
if (e->e.nil) {
|
|
|
|
|
return e->e.nil;
|
|
|
|
|
}
|
|
|
|
|
// fall through
|
2004-02-11 01:43:33 +00:00
|
|
|
|
case ex_state:
|
2001-10-17 07:45:37 +00:00
|
|
|
|
return &type_void;
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_block:
|
|
|
|
|
if (e->e.block.result)
|
|
|
|
|
return get_type (e->e.block.result);
|
2001-10-02 18:55:52 +00:00
|
|
|
|
return &type_void;
|
2001-06-20 07:02:36 +00:00
|
|
|
|
case ex_expr:
|
2001-06-20 21:18:04 +00:00
|
|
|
|
case ex_uexpr:
|
2020-03-28 03:10:23 +00:00
|
|
|
|
type = e->e.expr.type;
|
|
|
|
|
break;
|
2020-03-16 16:42:46 +00:00
|
|
|
|
case ex_def:
|
2020-03-28 03:10:23 +00:00
|
|
|
|
type = e->e.def->type;
|
|
|
|
|
break;
|
2011-01-13 05:54:24 +00:00
|
|
|
|
case ex_symbol:
|
2020-03-28 03:10:23 +00:00
|
|
|
|
type = e->e.symbol->type;
|
|
|
|
|
break;
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_temp:
|
2020-03-29 02:29:15 +00:00
|
|
|
|
type = e->e.temp.type;
|
|
|
|
|
break;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ex_value:
|
2020-03-28 03:10:23 +00:00
|
|
|
|
type = e->e.value->type;
|
|
|
|
|
break;
|
2013-06-24 06:37:08 +00:00
|
|
|
|
case ex_vector:
|
|
|
|
|
return e->e.vector.type;
|
2021-12-24 04:22:01 +00:00
|
|
|
|
case ex_selector:
|
|
|
|
|
return &type_SEL;
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
2022-01-08 09:49:35 +00:00
|
|
|
|
type = e->e.alias.type;
|
|
|
|
|
break;
|
2022-01-08 07:52:24 +00:00
|
|
|
|
case ex_address:
|
2022-01-08 09:49:35 +00:00
|
|
|
|
type = e->e.address.type;
|
|
|
|
|
break;
|
2022-01-08 09:44:29 +00:00
|
|
|
|
case ex_assign:
|
|
|
|
|
return get_type (e->e.assign.dst);
|
2022-01-24 09:35:16 +00:00
|
|
|
|
case ex_args:
|
|
|
|
|
return &type_va_list;
|
2022-01-30 01:56:15 +00:00
|
|
|
|
case ex_horizontal:
|
|
|
|
|
return e->e.hop.type;
|
2022-05-01 01:02:26 +00:00
|
|
|
|
case ex_swizzle:
|
|
|
|
|
return e->e.swizzle.type;
|
2022-08-18 08:46:14 +00:00
|
|
|
|
case ex_extend:
|
|
|
|
|
return e->e.extend.type;
|
2021-06-27 05:53:08 +00:00
|
|
|
|
case ex_count:
|
|
|
|
|
internal_error (e, "invalid expression");
|
2001-06-20 07:02:36 +00:00
|
|
|
|
}
|
2020-03-28 03:10:23 +00:00
|
|
|
|
return (type_t *) unalias_type (type);//FIXME cast
|
2001-10-02 18:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
etype_t
|
|
|
|
|
extract_type (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
type_t *type = get_type (e);
|
2001-12-06 19:49:40 +00:00
|
|
|
|
|
2001-10-02 18:55:52 +00:00
|
|
|
|
if (type)
|
|
|
|
|
return type->type;
|
2001-07-24 19:51:44 +00:00
|
|
|
|
return ev_type_count;
|
2001-06-20 07:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 08:55:03 +00:00
|
|
|
|
expr_t *
|
2001-07-23 01:31:22 +00:00
|
|
|
|
type_mismatch (expr_t *e1, expr_t *e2, int op)
|
|
|
|
|
{
|
2011-01-09 10:41:24 +00:00
|
|
|
|
e1 = error (e1, "type mismatch: %s %s %s",
|
2022-04-27 12:36:15 +00:00
|
|
|
|
get_type_string (get_type (e1)), get_op_string (op),
|
|
|
|
|
get_type_string (get_type (e2)));
|
2011-01-09 10:41:24 +00:00
|
|
|
|
return e1;
|
|
|
|
|
}
|
2004-11-02 07:13:00 +00:00
|
|
|
|
|
2011-01-09 10:41:24 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
param_mismatch (expr_t *e, int param, const char *fn, type_t *t1, type_t *t2)
|
|
|
|
|
{
|
2011-02-11 02:29:25 +00:00
|
|
|
|
e = error (e, "type mismatch for parameter %d of %s: expected %s, got %s",
|
2022-04-29 11:49:18 +00:00
|
|
|
|
param, fn, get_type_string (t1), get_type_string (t2));
|
2011-01-09 10:41:24 +00:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
test_error (expr_t *e, type_t *t)
|
|
|
|
|
{
|
|
|
|
|
dstring_t *s = dstring_newstr ();
|
|
|
|
|
|
|
|
|
|
print_type_str (s, t);
|
|
|
|
|
|
|
|
|
|
e = error (e, "%s cannot be tested", s->str);
|
|
|
|
|
dstring_delete (s);
|
|
|
|
|
return e;
|
2001-07-09 18:17:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-06-20 21:18:04 +00:00
|
|
|
|
expr_t *
|
2001-06-25 20:52:04 +00:00
|
|
|
|
new_expr (void)
|
2001-06-20 21:18:04 +00:00
|
|
|
|
{
|
2002-06-05 21:13:29 +00:00
|
|
|
|
expr_t *e;
|
|
|
|
|
|
|
|
|
|
ALLOC (16384, expr_t, exprs, e);
|
2001-12-06 19:49:40 +00:00
|
|
|
|
|
2002-07-03 21:32:03 +00:00
|
|
|
|
e->line = pr.source_line;
|
|
|
|
|
e->file = pr.source_file;
|
2001-06-26 16:23:21 +00:00
|
|
|
|
return e;
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-11 03:05:29 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
copy_expr (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
expr_t *n;
|
|
|
|
|
expr_t *t;
|
|
|
|
|
|
|
|
|
|
if (!e)
|
|
|
|
|
return 0;
|
|
|
|
|
switch (e->type) {
|
|
|
|
|
case ex_error:
|
2020-03-16 16:42:46 +00:00
|
|
|
|
case ex_def:
|
2011-01-13 05:54:24 +00:00
|
|
|
|
case ex_symbol:
|
2011-01-11 03:05:29 +00:00
|
|
|
|
case ex_nil:
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ex_value:
|
2011-01-11 03:05:29 +00:00
|
|
|
|
// nothing to do here
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2011-02-14 02:30:16 +00:00
|
|
|
|
n->line = pr.source_line;
|
|
|
|
|
n->file = pr.source_file;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
return n;
|
|
|
|
|
case ex_state:
|
|
|
|
|
return new_state_expr (copy_expr (e->e.state.frame),
|
|
|
|
|
copy_expr (e->e.state.think),
|
|
|
|
|
copy_expr (e->e.state.step));
|
|
|
|
|
case ex_bool:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2011-02-14 02:30:16 +00:00
|
|
|
|
n->line = pr.source_line;
|
|
|
|
|
n->file = pr.source_file;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
if (e->e.bool.true_list) {
|
|
|
|
|
int count = e->e.bool.true_list->size;
|
|
|
|
|
size_t size = (size_t)&((ex_list_t *) 0)->e[count];
|
|
|
|
|
n->e.bool.true_list = malloc (size);
|
|
|
|
|
while (count--)
|
|
|
|
|
n->e.bool.true_list->e[count] =
|
2012-11-26 07:13:40 +00:00
|
|
|
|
copy_expr (e->e.bool.true_list->e[count]);
|
2011-01-11 03:05:29 +00:00
|
|
|
|
}
|
|
|
|
|
if (e->e.bool.false_list) {
|
|
|
|
|
int count = e->e.bool.false_list->size;
|
|
|
|
|
size_t size = (size_t)&((ex_list_t *) 0)->e[count];
|
|
|
|
|
n->e.bool.false_list = malloc (size);
|
|
|
|
|
while (count--)
|
|
|
|
|
n->e.bool.false_list->e[count] =
|
2012-11-26 07:13:40 +00:00
|
|
|
|
copy_expr (e->e.bool.false_list->e[count]);
|
2011-01-11 03:05:29 +00:00
|
|
|
|
}
|
|
|
|
|
n->e.bool.e = copy_expr (e->e.bool.e);
|
|
|
|
|
return n;
|
|
|
|
|
case ex_label:
|
|
|
|
|
/// Create a fresh label
|
|
|
|
|
return new_label_expr ();
|
2012-11-03 09:08:32 +00:00
|
|
|
|
case ex_labelref:
|
|
|
|
|
return new_label_ref (e->e.labelref.label);
|
2011-01-11 03:05:29 +00:00
|
|
|
|
case ex_block:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2011-02-14 02:30:16 +00:00
|
|
|
|
n->line = pr.source_line;
|
|
|
|
|
n->file = pr.source_file;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
n->e.block.head = 0;
|
|
|
|
|
n->e.block.tail = &n->e.block.head;
|
|
|
|
|
n->e.block.result = 0;
|
|
|
|
|
for (t = e->e.block.head; t; t = t->next) {
|
|
|
|
|
if (t == e->e.block.result) {
|
|
|
|
|
n->e.block.result = copy_expr (t);
|
|
|
|
|
append_expr (n, n->e.block.result);
|
|
|
|
|
} else {
|
|
|
|
|
append_expr (n, copy_expr (t));
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-26 10:02:02 +00:00
|
|
|
|
if (e->e.block.result && !n->e.block.result)
|
|
|
|
|
internal_error (e, "bogus block result?");
|
2022-04-29 11:53:59 +00:00
|
|
|
|
return n;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
case ex_expr:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2011-02-14 02:30:16 +00:00
|
|
|
|
n->line = pr.source_line;
|
|
|
|
|
n->file = pr.source_file;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
n->e.expr.e1 = copy_expr (e->e.expr.e1);
|
|
|
|
|
n->e.expr.e2 = copy_expr (e->e.expr.e2);
|
|
|
|
|
return n;
|
|
|
|
|
case ex_uexpr:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2011-02-14 02:30:16 +00:00
|
|
|
|
n->line = pr.source_line;
|
|
|
|
|
n->file = pr.source_file;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
n->e.expr.e1 = copy_expr (e->e.expr.e1);
|
|
|
|
|
return n;
|
|
|
|
|
case ex_temp:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2011-02-14 02:30:16 +00:00
|
|
|
|
n->line = pr.source_line;
|
|
|
|
|
n->file = pr.source_file;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
return n;
|
2013-06-24 06:37:08 +00:00
|
|
|
|
case ex_vector:
|
|
|
|
|
n = new_expr ();
|
2021-06-27 05:53:08 +00:00
|
|
|
|
*n = *e;
|
2013-06-24 06:37:08 +00:00
|
|
|
|
n->e.vector.type = e->e.vector.type;
|
|
|
|
|
n->e.vector.list = copy_expr (e->e.vector.list);
|
|
|
|
|
t = e->e.vector.list;
|
2020-03-11 06:46:57 +00:00
|
|
|
|
e = n->e.vector.list;
|
2013-06-24 06:37:08 +00:00
|
|
|
|
while (t->next) {
|
2020-03-11 06:46:57 +00:00
|
|
|
|
e->next = copy_expr (t->next);
|
|
|
|
|
e = e->next;
|
2013-06-24 06:37:08 +00:00
|
|
|
|
t = t->next;
|
|
|
|
|
}
|
|
|
|
|
return n;
|
2021-12-24 04:22:01 +00:00
|
|
|
|
case ex_selector:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.selector.sel_ref = copy_expr (e->e.selector.sel_ref);
|
|
|
|
|
return n;
|
2020-03-11 06:46:57 +00:00
|
|
|
|
case ex_compound:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2020-03-11 10:42:38 +00:00
|
|
|
|
for (element_t *i = e->e.compound.head; i; i = i->next) {
|
|
|
|
|
append_element (n, new_element (i->expr, i->symbol));
|
2020-03-11 06:46:57 +00:00
|
|
|
|
}
|
|
|
|
|
return n;
|
2020-03-11 13:57:20 +00:00
|
|
|
|
case ex_memset:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.memset.dst = copy_expr (e->e.memset.dst);
|
|
|
|
|
n->e.memset.val = copy_expr (e->e.memset.val);
|
|
|
|
|
n->e.memset.count = copy_expr (e->e.memset.count);
|
|
|
|
|
return n;
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.alias.expr = copy_expr (e->e.alias.expr);
|
|
|
|
|
n->e.alias.offset = copy_expr (e->e.alias.offset);
|
|
|
|
|
return n;
|
2022-01-08 07:52:24 +00:00
|
|
|
|
case ex_address:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.address.lvalue = copy_expr (e->e.address.lvalue);
|
|
|
|
|
n->e.address.offset = copy_expr (e->e.address.offset);
|
|
|
|
|
return n;
|
2022-01-08 09:44:29 +00:00
|
|
|
|
case ex_assign:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.assign.dst = copy_expr (e->e.assign.dst);
|
|
|
|
|
n->e.assign.src = copy_expr (e->e.assign.src);
|
|
|
|
|
return n;
|
2022-01-09 05:02:16 +00:00
|
|
|
|
case ex_branch:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.branch.target = copy_expr (e->e.branch.target);
|
2022-01-21 04:09:23 +00:00
|
|
|
|
n->e.branch.index = copy_expr (e->e.branch.index);
|
2022-01-09 05:02:16 +00:00
|
|
|
|
n->e.branch.test = copy_expr (e->e.branch.test);
|
|
|
|
|
n->e.branch.args = copy_expr (e->e.branch.args);
|
|
|
|
|
return n;
|
2022-01-09 07:28:08 +00:00
|
|
|
|
case ex_return:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
2022-01-21 09:47:12 +00:00
|
|
|
|
n->e.retrn.ret_val = copy_expr (e->e.retrn.ret_val);
|
|
|
|
|
return n;
|
|
|
|
|
case ex_adjstk:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
return n;
|
|
|
|
|
case ex_with:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
n->e.with.with = copy_expr (e->e.with.with);
|
2022-01-09 07:28:08 +00:00
|
|
|
|
return n;
|
2022-01-24 09:35:16 +00:00
|
|
|
|
case ex_args:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
return n;
|
2022-01-30 01:56:15 +00:00
|
|
|
|
case ex_horizontal:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
e->e.hop.vec = copy_expr (e->e.hop.vec);
|
|
|
|
|
return n;
|
2022-05-01 01:02:26 +00:00
|
|
|
|
case ex_swizzle:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
e->e.swizzle.src = copy_expr (e->e.swizzle.src);
|
|
|
|
|
return n;
|
2022-08-18 08:46:14 +00:00
|
|
|
|
case ex_extend:
|
|
|
|
|
n = new_expr ();
|
|
|
|
|
*n = *e;
|
|
|
|
|
e->e.extend.src = copy_expr (e->e.extend.src);
|
|
|
|
|
return n;
|
2021-06-27 05:53:08 +00:00
|
|
|
|
case ex_count:
|
|
|
|
|
break;
|
2011-01-11 03:05:29 +00:00
|
|
|
|
}
|
2012-10-26 10:02:02 +00:00
|
|
|
|
internal_error (e, "invalid expression");
|
2011-01-11 03:05:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-10 16:52:45 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
expr_file_line (expr_t *dst, const expr_t *src)
|
|
|
|
|
{
|
|
|
|
|
dst->file = src->file;
|
|
|
|
|
dst->line = src->line;
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 08:58:54 +00:00
|
|
|
|
const char *
|
|
|
|
|
new_label_name (void)
|
2001-06-25 20:52:04 +00:00
|
|
|
|
{
|
2001-08-22 21:55:01 +00:00
|
|
|
|
static int label = 0;
|
|
|
|
|
int lnum = ++label;
|
2011-01-18 03:37:12 +00:00
|
|
|
|
const char *fname = current_func->sym->name;
|
2020-03-11 01:50:15 +00:00
|
|
|
|
const char *lname;
|
2001-12-06 19:49:40 +00:00
|
|
|
|
|
2021-01-31 07:01:20 +00:00
|
|
|
|
lname = save_string (va (0, "$%s_%d", fname, lnum));
|
2001-11-13 08:58:54 +00:00
|
|
|
|
return lname;
|
|
|
|
|
}
|
2011-02-06 23:30:28 +00:00
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
|
static expr_t *
|
2002-06-28 16:38:05 +00:00
|
|
|
|
new_error_expr (void)
|
2002-05-16 20:20:23 +00:00
|
|
|
|
{
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_error;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
2011-02-06 23:30:28 +00:00
|
|
|
|
|
2001-11-13 08:58:54 +00:00
|
|
|
|
expr_t *
|
2004-02-11 01:43:33 +00:00
|
|
|
|
new_state_expr (expr_t *frame, expr_t *think, expr_t *step)
|
2001-11-13 08:58:54 +00:00
|
|
|
|
{
|
2004-02-11 01:43:33 +00:00
|
|
|
|
expr_t *s = new_expr ();
|
2001-06-25 20:52:04 +00:00
|
|
|
|
|
2004-02-11 01:43:33 +00:00
|
|
|
|
s->type = ex_state;
|
|
|
|
|
s->e.state.frame = frame;
|
|
|
|
|
s->e.state.think = think;
|
|
|
|
|
s->e.state.step = step;
|
|
|
|
|
return s;
|
2001-06-25 20:52:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-22 08:05:17 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_bool_expr (ex_list_t *true_list, ex_list_t *false_list, expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
expr_t *b = new_expr ();
|
|
|
|
|
|
|
|
|
|
b->type = ex_bool;
|
|
|
|
|
b->e.bool.true_list = true_list;
|
|
|
|
|
b->e.bool.false_list = false_list;
|
|
|
|
|
b->e.bool.e = e;
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-11 01:43:33 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_label_expr (void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
expr_t *l = new_expr ();
|
|
|
|
|
|
|
|
|
|
l->type = ex_label;
|
|
|
|
|
l->e.label.name = new_label_name ();
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-11 02:31:54 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
named_label_expr (symbol_t *label)
|
|
|
|
|
{
|
|
|
|
|
symbol_t *sym;
|
2020-03-11 04:31:12 +00:00
|
|
|
|
expr_t *l;
|
2020-03-11 02:31:54 +00:00
|
|
|
|
|
|
|
|
|
if (!current_func) {
|
|
|
|
|
// XXX this might be only an error
|
|
|
|
|
internal_error (0, "label defined outside of function scope");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sym = symtab_lookup (current_func->label_scope, label->name);
|
|
|
|
|
|
|
|
|
|
if (sym) {
|
|
|
|
|
return sym->s.expr;
|
|
|
|
|
}
|
2020-03-11 04:31:12 +00:00
|
|
|
|
l = new_label_expr ();
|
2021-01-31 07:01:20 +00:00
|
|
|
|
l->e.label.name = save_string (va (0, "%s_%s", l->e.label.name,
|
|
|
|
|
label->name));
|
2020-03-11 04:31:12 +00:00
|
|
|
|
l->e.label.symbol = label;
|
2020-03-11 02:31:54 +00:00
|
|
|
|
label->sy_type = sy_expr;
|
2020-03-11 04:31:12 +00:00
|
|
|
|
label->s.expr = l;
|
2020-03-11 02:31:54 +00:00
|
|
|
|
symtab_addsymbol (current_func->label_scope, label);
|
|
|
|
|
return label->s.expr;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 09:08:32 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_label_ref (ex_label_t *label)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
expr_t *l = new_expr ();
|
|
|
|
|
|
|
|
|
|
l->type = ex_labelref;
|
|
|
|
|
l->e.labelref.label = label;
|
|
|
|
|
label->used++;
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-26 03:33:01 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_block_expr (void)
|
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *b = new_expr ();
|
2001-06-26 03:33:01 +00:00
|
|
|
|
|
|
|
|
|
b->type = ex_block;
|
|
|
|
|
b->e.block.head = 0;
|
|
|
|
|
b->e.block.tail = &b->e.block.head;
|
2020-03-14 03:27:23 +00:00
|
|
|
|
b->e.block.return_addr = __builtin_return_address (0);
|
2001-06-26 03:33:01 +00:00
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-26 02:46:02 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_binary_expr (int op, expr_t *e1, expr_t *e2)
|
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *e = new_expr ();
|
2001-06-26 02:46:02 +00:00
|
|
|
|
|
2002-06-28 16:38:05 +00:00
|
|
|
|
if (e1->type == ex_error)
|
|
|
|
|
return e1;
|
|
|
|
|
if (e2 && e2->type == ex_error)
|
|
|
|
|
return e2;
|
|
|
|
|
|
2001-06-26 02:46:02 +00:00
|
|
|
|
e->type = ex_expr;
|
|
|
|
|
e->e.expr.op = op;
|
|
|
|
|
e->e.expr.e1 = e1;
|
|
|
|
|
e->e.expr.e2 = e2;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-09 04:54:03 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
build_block_expr (expr_t *expr_list)
|
|
|
|
|
{
|
|
|
|
|
expr_t *b = new_block_expr ();
|
|
|
|
|
|
|
|
|
|
while (expr_list) {
|
|
|
|
|
expr_t *e = expr_list;
|
|
|
|
|
expr_list = e->next;
|
|
|
|
|
e->next = 0;
|
|
|
|
|
append_expr (b, e);
|
|
|
|
|
}
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-26 02:46:02 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_unary_expr (int op, expr_t *e1)
|
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *e = new_expr ();
|
2001-06-26 02:46:02 +00:00
|
|
|
|
|
2002-06-28 16:38:05 +00:00
|
|
|
|
if (e1 && e1->type == ex_error)
|
|
|
|
|
return e1;
|
|
|
|
|
|
2001-06-26 02:46:02 +00:00
|
|
|
|
e->type = ex_uexpr;
|
|
|
|
|
e->e.expr.op = op;
|
|
|
|
|
e->e.expr.e1 = e1;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-30 01:56:15 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_horizontal_expr (int op, expr_t *vec, type_t *type)
|
|
|
|
|
{
|
|
|
|
|
type_t *vec_type = get_type (vec);
|
|
|
|
|
if (!vec_type) {
|
|
|
|
|
return vec;
|
|
|
|
|
}
|
|
|
|
|
if (!is_math (vec_type) || is_scalar (vec_type)) {
|
|
|
|
|
internal_error (vec, "horizontal operand not a vector type");
|
|
|
|
|
}
|
|
|
|
|
if (!is_scalar (type)) {
|
|
|
|
|
internal_error (vec, "horizontal result not a scalar type");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_horizontal;
|
|
|
|
|
e->e.hop.op = op;
|
|
|
|
|
e->e.hop.vec = vec;
|
|
|
|
|
e->e.hop.type = type;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-01 01:02:26 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_swizzle_expr (expr_t *src, const char *swizzle)
|
|
|
|
|
{
|
|
|
|
|
type_t *src_type = get_type (src);
|
|
|
|
|
if (!src_type) {
|
|
|
|
|
return src;
|
|
|
|
|
}
|
|
|
|
|
int src_width = type_width (src_type);
|
|
|
|
|
// swizzle always generates a *vec4
|
|
|
|
|
ex_swizzle_t swiz = {};
|
|
|
|
|
|
|
|
|
|
#define m(x) (1 << ((x) - 'a'))
|
|
|
|
|
#define v(x, mask) (((x) & 0x60) == 0x60 && (m(x) & (mask)))
|
|
|
|
|
#define vind(x) ((x) & 3)
|
|
|
|
|
#define cind(x) (-(((x) >> 3) ^ (x)) & 3)
|
|
|
|
|
#define tind(x) ((((~(x+1)>>2)&1) + x + 1) & 3)
|
|
|
|
|
const int color = m('r') | m('g') | m('b') | m('a');
|
|
|
|
|
const int vector = m('x') | m('y') | m('z') | m('w');
|
|
|
|
|
const int texture = m('s') | m('t') | m('p') | m('q');
|
|
|
|
|
|
|
|
|
|
int type_mask = 0;
|
|
|
|
|
int comp_count = 0;
|
|
|
|
|
|
|
|
|
|
for (const char *s = swizzle; *s; s++) {
|
|
|
|
|
if (comp_count >= 4) {
|
|
|
|
|
return error (src, "too many components in swizzle");
|
|
|
|
|
}
|
|
|
|
|
if (*s == '0') {
|
|
|
|
|
swiz.zero |= 1 << comp_count;
|
|
|
|
|
comp_count++;
|
|
|
|
|
} else if (*s == '-') {
|
|
|
|
|
swiz.neg |= 1 << comp_count;
|
|
|
|
|
} else {
|
|
|
|
|
int ind = 0;
|
|
|
|
|
int mask = 0;
|
|
|
|
|
if (v (*s, vector)) {
|
|
|
|
|
ind = vind (*s);
|
|
|
|
|
mask = 1;
|
|
|
|
|
} else if (v (*s, color)) {
|
|
|
|
|
ind = cind (*s);
|
|
|
|
|
mask = 2;
|
|
|
|
|
} else if (v (*s, texture)) {
|
|
|
|
|
ind = tind (*s);
|
|
|
|
|
mask = 4;
|
|
|
|
|
}
|
|
|
|
|
if (!mask) {
|
|
|
|
|
return error (src, "invalid component in swizzle");
|
|
|
|
|
}
|
|
|
|
|
if (type_mask & ~mask) {
|
|
|
|
|
return error (src, "mixed components in swizzle");
|
|
|
|
|
}
|
|
|
|
|
if (ind >= src_width) {
|
|
|
|
|
return error (src, "swizzle component out of bounds");
|
|
|
|
|
}
|
|
|
|
|
type_mask |= mask;
|
|
|
|
|
swiz.source[comp_count++] = ind;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
swiz.zero |= (0xf << comp_count) & 0xf;
|
|
|
|
|
swiz.src = new_alias_expr (vector_type (&type_float, src_width), src);
|
|
|
|
|
swiz.type = vector_type (base_type (src_type), 4);
|
|
|
|
|
|
|
|
|
|
expr_t *expr = new_expr ();
|
|
|
|
|
expr->type = ex_swizzle;
|
|
|
|
|
expr->e.swizzle = swiz;
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-18 08:46:14 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_extend_expr (expr_t *src, type_t *type, int ext)
|
|
|
|
|
{
|
|
|
|
|
expr_t *expr = new_expr ();
|
|
|
|
|
expr->type = ex_extend;
|
|
|
|
|
expr->e.extend.src = src;
|
|
|
|
|
expr->e.extend.extend = ext;
|
|
|
|
|
expr->e.extend.type = type;
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-16 16:42:46 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_def_expr (def_t *def)
|
|
|
|
|
{
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_def;
|
|
|
|
|
e->e.def = def;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-13 05:54:24 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_symbol_expr (symbol_t *symbol)
|
|
|
|
|
{
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_symbol;
|
|
|
|
|
e->e.symbol = symbol;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-11 21:15:24 +00:00
|
|
|
|
expr_t *
|
2020-03-28 03:10:23 +00:00
|
|
|
|
new_temp_def_expr (const type_t *type)
|
2001-08-11 21:15:24 +00:00
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *e = new_expr ();
|
2001-08-11 21:15:24 +00:00
|
|
|
|
|
|
|
|
|
e->type = ex_temp;
|
2020-03-28 03:10:23 +00:00
|
|
|
|
e->e.temp.type = (type_t *) unalias_type (type); // FIXME cast
|
2001-08-11 21:15:24 +00:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-13 18:49:27 +00:00
|
|
|
|
expr_t *
|
2002-09-11 16:21:26 +00:00
|
|
|
|
new_nil_expr (void)
|
2001-11-13 18:49:27 +00:00
|
|
|
|
{
|
2002-09-11 16:21:26 +00:00
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_nil;
|
2001-11-13 18:49:27 +00:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-24 09:35:16 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_args_expr (void)
|
|
|
|
|
{
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_args;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-23 10:29:50 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_value_expr (ex_value_t *value)
|
|
|
|
|
{
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
e->type = ex_value;
|
|
|
|
|
e->e.value = value;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-21 19:03:29 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_name_expr (const char *name)
|
|
|
|
|
{
|
|
|
|
|
expr_t *e = new_expr ();
|
2011-01-17 13:33:33 +00:00
|
|
|
|
symbol_t *sym;
|
|
|
|
|
|
|
|
|
|
sym = symtab_lookup (current_symtab, name);
|
|
|
|
|
if (!sym)
|
2011-02-08 08:09:27 +00:00
|
|
|
|
sym = new_symbol (name);
|
2011-01-17 13:33:33 +00:00
|
|
|
|
e->type = ex_symbol;
|
|
|
|
|
e->e.symbol = sym;
|
2002-01-21 19:03:29 +00:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-09 20:12:28 +00:00
|
|
|
|
expr_t *
|
2002-09-11 16:21:26 +00:00
|
|
|
|
new_string_expr (const char *string_val)
|
2002-05-09 20:12:28 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_string_val (string_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 07:38:37 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_double_expr (double double_val)
|
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_double_val (double_val));
|
2020-02-14 07:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-11 16:21:26 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_float_expr (float float_val)
|
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_float_val (float_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
2011-01-10 23:43:34 +00:00
|
|
|
|
new_vector_expr (const float *vector_val)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_vector_val (vector_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
new_entity_expr (int entity_val)
|
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_entity_val (entity_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
2004-11-12 10:49:00 +00:00
|
|
|
|
new_field_expr (int field_val, type_t *type, def_t *def)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_field_val (field_val, type, def));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
2012-11-21 01:06:15 +00:00
|
|
|
|
new_func_expr (int func_val, type_t *type)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_func_val (func_val, type));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-09 04:12:44 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_pointer_expr (int val, type_t *type, def_t *def)
|
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_pointer_val (val, type, def, 0));
|
2004-04-09 04:12:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-11 16:21:26 +00:00
|
|
|
|
expr_t *
|
2011-01-10 23:43:34 +00:00
|
|
|
|
new_quaternion_expr (const float *quaternion_val)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_quaternion_val (quaternion_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
2022-01-18 04:21:06 +00:00
|
|
|
|
new_int_expr (int int_val)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_int_val (int_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-09 01:07:47 +00:00
|
|
|
|
expr_t *
|
2022-01-18 04:21:06 +00:00
|
|
|
|
new_uint_expr (unsigned uint_val)
|
2011-04-09 01:07:47 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_uint_val (uint_val));
|
2011-04-09 01:07:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-29 06:38:55 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_long_expr (pr_long_t long_val)
|
|
|
|
|
{
|
|
|
|
|
return new_value_expr (new_long_val (long_val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
new_ulong_expr (pr_ulong_t ulong_val)
|
|
|
|
|
{
|
|
|
|
|
return new_value_expr (new_ulong_val (ulong_val));
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-11 16:21:26 +00:00
|
|
|
|
expr_t *
|
2011-01-18 23:41:24 +00:00
|
|
|
|
new_short_expr (short short_val)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-04-28 08:37:56 +00:00
|
|
|
|
return new_value_expr (new_short_val (short_val));
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-18 23:41:24 +00:00
|
|
|
|
int
|
|
|
|
|
is_constant (expr_t *e)
|
2002-09-11 16:21:26 +00:00
|
|
|
|
{
|
2022-01-08 03:06:52 +00:00
|
|
|
|
while (e->type == ex_alias) {
|
|
|
|
|
e = e->e.alias.expr;
|
2020-02-15 06:37:16 +00:00
|
|
|
|
}
|
2012-11-03 09:08:32 +00:00
|
|
|
|
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref
|
2011-03-30 10:58:09 +00:00
|
|
|
|
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_const)
|
|
|
|
|
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant))
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
2002-09-11 16:21:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-29 09:24:16 +00:00
|
|
|
|
int
|
|
|
|
|
is_variable (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
while (e->type == ex_alias) {
|
|
|
|
|
e = e->e.alias.expr;
|
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_def
|
|
|
|
|
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_var)
|
|
|
|
|
|| e->type == ex_temp) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-24 04:58:16 +00:00
|
|
|
|
int
|
|
|
|
|
is_selector (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
return e->type == ex_selector;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-15 00:28:27 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
constant_expr (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
expr_t *new;
|
2011-04-09 03:42:41 +00:00
|
|
|
|
symbol_t *sym;
|
2012-07-18 14:01:09 +00:00
|
|
|
|
ex_value_t *value;
|
2011-04-09 03:42:41 +00:00
|
|
|
|
|
2011-02-15 00:28:27 +00:00
|
|
|
|
if (!is_constant (e))
|
|
|
|
|
return e;
|
2012-11-03 09:08:32 +00:00
|
|
|
|
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref)
|
2011-02-15 00:28:27 +00:00
|
|
|
|
return e;
|
2011-04-09 03:42:41 +00:00
|
|
|
|
if (e->type != ex_symbol)
|
|
|
|
|
return e;
|
|
|
|
|
sym = e->e.symbol;
|
|
|
|
|
if (sym->sy_type == sy_const) {
|
|
|
|
|
value = sym->s.value;
|
|
|
|
|
} else if (sym->sy_type == sy_var && sym->s.def->constant) {
|
|
|
|
|
//FIXME pointers and fields
|
2012-07-18 14:01:09 +00:00
|
|
|
|
internal_error (e, "what to do here?");
|
|
|
|
|
//memset (&value, 0, sizeof (value));
|
|
|
|
|
//memcpy (&value.v, &D_INT (sym->s.def),
|
|
|
|
|
//type_size (sym->s.def->type) * sizeof (pr_type_t));
|
2011-04-09 03:42:41 +00:00
|
|
|
|
} else {
|
2011-02-15 00:28:27 +00:00
|
|
|
|
return e;
|
2011-04-09 03:42:41 +00:00
|
|
|
|
}
|
2022-04-28 08:37:56 +00:00
|
|
|
|
new = new_value_expr (value);
|
2011-02-15 00:28:27 +00:00
|
|
|
|
new->line = e->line;
|
|
|
|
|
new->file = e->file;
|
|
|
|
|
return new;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-11 13:57:48 +00:00
|
|
|
|
int
|
|
|
|
|
is_nil (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
return e->type == ex_nil;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 08:55:03 +00:00
|
|
|
|
int
|
2011-01-18 23:41:24 +00:00
|
|
|
|
is_string_val (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 1;
|
2018-10-12 13:05:17 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_string)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_string)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
expr_string (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 0;
|
2018-10-12 13:05:17 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_string)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.value->v.string_val;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, "not a string constant");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
is_float_val (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 1;
|
2018-10-12 13:05:17 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_float)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_float)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 07:38:37 +00:00
|
|
|
|
double
|
|
|
|
|
expr_double (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 0;
|
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_double)
|
|
|
|
|
return e->e.value->v.double_val;
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_double)
|
|
|
|
|
return e->e.symbol->s.value->v.double_val;
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant
|
|
|
|
|
&& is_double (e->e.symbol->s.def->type))
|
2020-02-14 09:15:34 +00:00
|
|
|
|
return D_DOUBLE (e->e.symbol->s.def);
|
2020-02-14 07:38:37 +00:00
|
|
|
|
internal_error (e, "not a double constant");
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-18 23:41:24 +00:00
|
|
|
|
float
|
|
|
|
|
expr_float (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 0;
|
2018-10-12 13:05:17 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_float)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.value->v.float_val;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_float)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.symbol->s.value->v.float_val;
|
2011-03-30 10:58:09 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant
|
|
|
|
|
&& is_float (e->e.symbol->s.def->type))
|
|
|
|
|
return D_FLOAT (e->e.symbol->s.def);
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, "not a float constant");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
is_vector_val (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 1;
|
2018-10-12 13:05:17 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_vector)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_vector)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float *
|
|
|
|
|
expr_vector (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return vec3_origin;
|
2018-10-12 13:05:17 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_vector)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.value->v.vector_val;
|
2011-01-19 02:09:54 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_vector)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.symbol->s.value->v.vector_val;
|
2011-04-04 12:31:59 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant
|
|
|
|
|
&& e->e.symbol->s.def->type->type == ev_vector)
|
|
|
|
|
return D_VECTOR (e->e.symbol->s.def);
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, "not a vector constant");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
is_quaternion_val (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return 1;
|
2022-01-18 06:48:43 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_quaternion)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2022-01-18 06:48:43 +00:00
|
|
|
|
&& e->e.symbol->type->type == ev_quaternion)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float *
|
|
|
|
|
expr_quaternion (expr_t *e)
|
2004-01-25 08:55:03 +00:00
|
|
|
|
{
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (e->type == ex_nil)
|
|
|
|
|
return quat_origin;
|
2022-01-18 06:48:43 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_quaternion)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.value->v.quaternion_val;
|
2011-01-19 02:09:54 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2022-01-18 06:48:43 +00:00
|
|
|
|
&& e->e.symbol->type->type == ev_quaternion)
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.symbol->s.value->v.quaternion_val;
|
2011-04-04 12:31:59 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant
|
2022-01-18 06:48:43 +00:00
|
|
|
|
&& e->e.symbol->s.def->type->type == ev_quaternion)
|
2011-04-04 12:31:59 +00:00
|
|
|
|
return D_QUAT (e->e.symbol->s.def);
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, "not a quaternion constant");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2022-01-18 04:21:06 +00:00
|
|
|
|
is_int_val (expr_t *e)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
{
|
2020-03-17 01:55:27 +00:00
|
|
|
|
if (e->type == ex_nil) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_int) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2020-03-17 01:55:27 +00:00
|
|
|
|
&& is_integral (e->e.symbol->type)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2020-03-17 01:56:45 +00:00
|
|
|
|
if (e->type == ex_def && e->e.def->constant
|
|
|
|
|
&& is_integral (e->e.def->type)) {
|
2004-01-25 08:55:03 +00:00
|
|
|
|
return 1;
|
2020-03-17 01:56:45 +00:00
|
|
|
|
}
|
2004-01-25 08:55:03 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-18 23:41:24 +00:00
|
|
|
|
int
|
2022-01-18 04:21:06 +00:00
|
|
|
|
expr_int (expr_t *e)
|
2011-01-18 23:41:24 +00:00
|
|
|
|
{
|
2020-03-17 01:55:27 +00:00
|
|
|
|
if (e->type == ex_nil) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 0;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_int) {
|
|
|
|
|
return e->e.value->v.int_val;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2022-01-25 03:47:12 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_short) {
|
|
|
|
|
return e->e.value->v.short_val;
|
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2022-01-18 04:21:06 +00:00
|
|
|
|
&& (e->e.symbol->type->type == ev_int
|
2020-03-17 01:55:27 +00:00
|
|
|
|
|| is_enum (e->e.symbol->type))) {
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return e->e.symbol->s.value->v.int_val;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-03-30 10:58:09 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant
|
2020-03-17 01:55:27 +00:00
|
|
|
|
&& is_integral (e->e.symbol->s.def->type)) {
|
2011-03-30 10:58:09 +00:00
|
|
|
|
return D_INT (e->e.symbol->s.def);
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2020-03-17 01:56:45 +00:00
|
|
|
|
if (e->type == ex_def && e->e.def->constant
|
|
|
|
|
&& is_integral (e->e.def->type)) {
|
|
|
|
|
return D_INT (e->e.def);
|
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
internal_error (e, "not an int constant");
|
2011-01-18 23:41:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 02:07:50 +00:00
|
|
|
|
int
|
2022-01-18 04:21:06 +00:00
|
|
|
|
is_uint_val (expr_t *e)
|
2020-03-17 02:07:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_uint) {
|
2020-03-17 02:07:50 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& is_integral (e->e.symbol->type)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_def && e->e.def->constant
|
|
|
|
|
&& is_integral (e->e.def->type)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-09 01:07:47 +00:00
|
|
|
|
unsigned
|
2022-01-18 04:21:06 +00:00
|
|
|
|
expr_uint (expr_t *e)
|
2011-04-09 01:07:47 +00:00
|
|
|
|
{
|
2020-03-17 01:55:27 +00:00
|
|
|
|
if (e->type == ex_nil) {
|
2011-04-09 01:07:47 +00:00
|
|
|
|
return 0;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_uint) {
|
|
|
|
|
return e->e.value->v.uint_val;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-04-09 01:07:47 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2022-01-18 04:21:06 +00:00
|
|
|
|
&& e->e.symbol->type->type == ev_uint) {
|
|
|
|
|
return e->e.symbol->s.value->v.uint_val;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-04-09 01:07:47 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
|
|
|
|
|
&& e->e.symbol->s.def->constant
|
2020-03-17 01:55:27 +00:00
|
|
|
|
&& is_integral (e->e.symbol->s.def->type)) {
|
2011-04-09 01:07:47 +00:00
|
|
|
|
return D_INT (e->e.symbol->s.def);
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2020-03-17 01:56:45 +00:00
|
|
|
|
if (e->type == ex_def && e->e.def->constant
|
|
|
|
|
&& is_integral (e->e.def->type)) {
|
|
|
|
|
return D_INT (e->e.def);
|
|
|
|
|
}
|
2011-04-09 01:07:47 +00:00
|
|
|
|
internal_error (e, "not an unsigned constant");
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-18 23:41:24 +00:00
|
|
|
|
int
|
|
|
|
|
is_short_val (expr_t *e)
|
|
|
|
|
{
|
2020-03-17 01:55:27 +00:00
|
|
|
|
if (e->type == ex_nil) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_short) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2020-03-17 01:55:27 +00:00
|
|
|
|
&& e->e.symbol->type->type == ev_short) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 1;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
short
|
|
|
|
|
expr_short (expr_t *e)
|
|
|
|
|
{
|
2020-03-17 01:55:27 +00:00
|
|
|
|
if (e->type == ex_nil) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
return 0;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_short) {
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.value->v.short_val;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
2020-03-17 01:55:27 +00:00
|
|
|
|
&& e->e.symbol->type->type == ev_short) {
|
2012-07-18 14:01:09 +00:00
|
|
|
|
return e->e.symbol->s.value->v.short_val;
|
2020-03-17 01:55:27 +00:00
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, "not a short constant");
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-27 12:36:15 +00:00
|
|
|
|
unsigned short
|
|
|
|
|
expr_ushort (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->type == ex_nil) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_ushort) {
|
|
|
|
|
return e->e.value->v.ushort_val;
|
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
|
|
|
|
|
&& e->e.symbol->type->type == ev_ushort) {
|
|
|
|
|
return e->e.symbol->s.value->v.ushort_val;
|
|
|
|
|
}
|
|
|
|
|
internal_error (e, "not a ushort constant");
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 02:07:50 +00:00
|
|
|
|
int
|
|
|
|
|
is_integral_val (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (is_constant (e)) {
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (e)) {
|
2020-03-17 02:07:50 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_uint_val (e)) {
|
2020-03-17 02:07:50 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (is_short_val (e)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
expr_integral (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (is_constant (e)) {
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (e)) {
|
|
|
|
|
return expr_int (e);
|
2020-03-17 02:07:50 +00:00
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_uint_val (e)) {
|
|
|
|
|
return expr_uint (e);
|
2020-03-17 02:07:50 +00:00
|
|
|
|
}
|
|
|
|
|
if (is_short_val (e)) {
|
|
|
|
|
return expr_short (e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
internal_error (e, "not an integral constant");
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 02:19:12 +00:00
|
|
|
|
int
|
|
|
|
|
is_pointer_val (expr_t *e)
|
|
|
|
|
{
|
2022-01-18 05:36:06 +00:00
|
|
|
|
if (e->type == ex_value && e->e.value->lltype == ev_ptr) {
|
2020-03-17 02:19:12 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-03 02:06:10 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_alias_expr (type_t *type, expr_t *expr)
|
|
|
|
|
{
|
2022-02-03 05:35:43 +00:00
|
|
|
|
if (is_ptr (type) && expr->type == ex_address) {
|
|
|
|
|
// avoid aliasing a pointer to a pointer (redundant)
|
|
|
|
|
expr = copy_expr (expr);
|
|
|
|
|
expr->e.address.type = type;
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
2022-01-08 03:06:52 +00:00
|
|
|
|
if (expr->type == ex_alias) {
|
2022-01-25 14:39:17 +00:00
|
|
|
|
if (expr->e.alias.offset) {
|
|
|
|
|
return new_offset_alias_expr (type, expr, 0);
|
|
|
|
|
}
|
|
|
|
|
expr = expr->e.alias.expr;
|
2019-06-17 13:48:42 +00:00
|
|
|
|
}
|
2022-01-28 06:29:40 +00:00
|
|
|
|
// this can happen when constant folding an offset pointer results in
|
|
|
|
|
// a noop due to the offset being 0 and thus casting back to the original
|
|
|
|
|
// type
|
|
|
|
|
if (type == get_type (expr)) {
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
2022-01-08 03:06:52 +00:00
|
|
|
|
|
|
|
|
|
expr_t *alias = new_expr ();
|
|
|
|
|
alias->type = ex_alias;
|
|
|
|
|
alias->e.alias.type = type;
|
|
|
|
|
alias->e.alias.expr = expr;
|
2012-05-03 04:27:30 +00:00
|
|
|
|
alias->file = expr->file;
|
|
|
|
|
alias->line = expr->line;
|
2011-03-03 02:06:10 +00:00
|
|
|
|
return alias;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-10 09:13:28 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_offset_alias_expr (type_t *type, expr_t *expr, int offset)
|
|
|
|
|
{
|
2022-01-08 03:06:52 +00:00
|
|
|
|
if (expr->type == ex_alias && expr->e.alias.offset) {
|
|
|
|
|
expr_t *ofs_expr = expr->e.alias.offset;
|
2019-06-17 13:48:42 +00:00
|
|
|
|
if (!is_constant (ofs_expr)) {
|
|
|
|
|
internal_error (ofs_expr, "non-constant offset for alias expr");
|
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
offset += expr_int (ofs_expr);
|
2022-01-08 03:06:52 +00:00
|
|
|
|
|
|
|
|
|
if (expr->e.alias.expr->type == ex_alias) {
|
|
|
|
|
internal_error (expr, "alias expr of alias expr");
|
|
|
|
|
}
|
|
|
|
|
expr = expr->e.alias.expr;
|
2019-06-17 13:48:42 +00:00
|
|
|
|
}
|
2022-01-08 03:06:52 +00:00
|
|
|
|
|
|
|
|
|
expr_t *alias = new_expr ();
|
|
|
|
|
alias->type = ex_alias;
|
|
|
|
|
alias->e.alias.type = type;
|
|
|
|
|
alias->e.alias.expr = expr;
|
2022-01-18 04:21:06 +00:00
|
|
|
|
alias->e.alias.offset = new_int_expr (offset);
|
2019-06-10 09:13:28 +00:00
|
|
|
|
alias->file = expr->file;
|
|
|
|
|
alias->line = expr->line;
|
|
|
|
|
return alias;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-08 07:52:24 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_address_expr (type_t *lvtype, expr_t *lvalue, expr_t *offset)
|
|
|
|
|
{
|
|
|
|
|
expr_t *addr = new_expr ();
|
|
|
|
|
addr->type = ex_address;
|
|
|
|
|
addr->e.address.type = pointer_type (lvtype);
|
|
|
|
|
addr->e.address.lvalue = lvalue;
|
|
|
|
|
addr->e.address.offset = offset;
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-08 09:44:29 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_assign_expr (expr_t *dst, expr_t *src)
|
|
|
|
|
{
|
|
|
|
|
expr_t *addr = new_expr ();
|
|
|
|
|
addr->type = ex_assign;
|
|
|
|
|
addr->e.assign.dst = dst;
|
|
|
|
|
addr->e.assign.src = src;
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 07:28:08 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_return_expr (expr_t *ret_val)
|
|
|
|
|
{
|
|
|
|
|
expr_t *retrn = new_expr ();
|
|
|
|
|
retrn->type = ex_return;
|
|
|
|
|
retrn->e.retrn.ret_val = ret_val;
|
|
|
|
|
return retrn;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 09:47:12 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
new_adjstk_expr (int mode, int offset)
|
|
|
|
|
{
|
|
|
|
|
expr_t *adj = new_expr ();
|
|
|
|
|
adj->type = ex_adjstk;
|
|
|
|
|
adj->e.adjstk.mode = mode;
|
|
|
|
|
adj->e.adjstk.offset = offset;
|
|
|
|
|
return adj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
new_with_expr (int mode, int reg, expr_t *val)
|
|
|
|
|
{
|
|
|
|
|
expr_t *with = new_expr ();
|
|
|
|
|
with->type = ex_with;
|
|
|
|
|
with->e.with.mode = mode;
|
|
|
|
|
with->e.with.reg = reg;
|
|
|
|
|
with->e.with.with = val;
|
|
|
|
|
return with;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-22 15:29:32 +00:00
|
|
|
|
static expr_t *
|
|
|
|
|
param_expr (const char *name, type_t *type)
|
|
|
|
|
{
|
2011-01-25 23:01:24 +00:00
|
|
|
|
symbol_t *sym;
|
2011-01-19 13:19:26 +00:00
|
|
|
|
expr_t *sym_expr;
|
2003-04-22 15:29:32 +00:00
|
|
|
|
|
2012-12-02 01:11:30 +00:00
|
|
|
|
sym = make_symbol (name, &type_param, pr.symtab->space, sc_extern);
|
2011-03-04 23:37:51 +00:00
|
|
|
|
if (!sym->table)
|
|
|
|
|
symtab_addsymbol (pr.symtab, sym);
|
2011-01-19 13:19:26 +00:00
|
|
|
|
sym_expr = new_symbol_expr (sym);
|
2011-03-03 02:06:10 +00:00
|
|
|
|
return new_alias_expr (type, sym_expr);
|
2003-04-22 15:29:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
new_ret_expr (type_t *type)
|
|
|
|
|
{
|
|
|
|
|
return param_expr (".return", type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
new_param_expr (type_t *type, int num)
|
|
|
|
|
{
|
2021-01-31 07:01:20 +00:00
|
|
|
|
return param_expr (va (0, ".param_%d", num), type);
|
2003-04-22 15:29:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-06-26 03:33:01 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
append_expr (expr_t *block, expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (block->type != ex_block)
|
2012-10-26 10:02:02 +00:00
|
|
|
|
internal_error (block, "not a block expression");
|
2001-06-26 03:33:01 +00:00
|
|
|
|
|
2002-06-28 16:38:05 +00:00
|
|
|
|
if (!e || e->type == ex_error)
|
2001-06-26 03:33:01 +00:00
|
|
|
|
return block;
|
|
|
|
|
|
2012-10-26 10:02:02 +00:00
|
|
|
|
if (e->next)
|
|
|
|
|
internal_error (e, "append_expr: expr loop detected");
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
|
|
2001-06-26 03:33:01 +00:00
|
|
|
|
*block->e.block.tail = e;
|
|
|
|
|
block->e.block.tail = &e->next;
|
|
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-24 07:44:48 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
prepend_expr (expr_t *block, expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
if (block->type != ex_block)
|
|
|
|
|
internal_error (block, "not a block expression");
|
|
|
|
|
|
|
|
|
|
if (!e || e->type == ex_error)
|
|
|
|
|
return block;
|
|
|
|
|
|
|
|
|
|
if (e->next)
|
|
|
|
|
internal_error (e, "append_expr: expr loop detected");
|
|
|
|
|
|
|
|
|
|
e->next = block->e.block.head;
|
|
|
|
|
block->e.block.head = e;
|
|
|
|
|
|
|
|
|
|
if (block->e.block.tail == &block->e.block.head) {
|
|
|
|
|
block->e.block.tail = &e->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 01:01:21 +00:00
|
|
|
|
static symbol_t *
|
2020-02-19 10:16:07 +00:00
|
|
|
|
get_struct_field (const type_t *t1, expr_t *e1, expr_t *e2)
|
2011-03-07 01:01:21 +00:00
|
|
|
|
{
|
2022-01-08 09:48:23 +00:00
|
|
|
|
symtab_t *strct = t1->t.symtab;
|
2011-03-07 01:01:21 +00:00
|
|
|
|
symbol_t *sym = e2->e.symbol;//FIXME need to check
|
|
|
|
|
symbol_t *field;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
|
2011-03-07 01:01:21 +00:00
|
|
|
|
if (!strct) {
|
|
|
|
|
error (e1, "dereferencing pointer to incomplete type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
field = symtab_lookup (strct, sym->name);
|
2020-03-27 06:16:41 +00:00
|
|
|
|
if (!field && !is_entity(t1)) {
|
2022-04-29 02:31:45 +00:00
|
|
|
|
const char *name = t1->name;
|
|
|
|
|
if (!strncmp (name, "tag ", 4)) {
|
|
|
|
|
name += 4;
|
|
|
|
|
}
|
|
|
|
|
error (e2, "'%s' has no member named '%s'", name, sym->name);
|
2011-03-07 01:01:21 +00:00
|
|
|
|
e1->type = ex_error;
|
|
|
|
|
}
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-27 08:43:33 +00:00
|
|
|
|
expr_t *
|
2001-06-20 21:18:04 +00:00
|
|
|
|
field_expr (expr_t *e1, expr_t *e2)
|
|
|
|
|
{
|
2020-02-19 10:16:07 +00:00
|
|
|
|
const type_t *t1, *t2;
|
2011-02-06 23:30:28 +00:00
|
|
|
|
expr_t *e;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
|
2020-02-22 05:04:10 +00:00
|
|
|
|
t1 = get_type (e1);
|
2011-02-06 23:30:28 +00:00
|
|
|
|
if (e1->type == ex_error)
|
|
|
|
|
return e1;
|
2022-01-25 03:46:14 +00:00
|
|
|
|
if (is_entity (t1)) {
|
2011-03-08 10:28:11 +00:00
|
|
|
|
symbol_t *field = 0;
|
|
|
|
|
|
|
|
|
|
if (e2->type == ex_symbol)
|
|
|
|
|
field = get_struct_field (&type_entity, e1, e2);
|
|
|
|
|
if (field) {
|
|
|
|
|
e2 = new_field_expr (0, field->type, field->s.def);
|
2011-02-06 23:30:28 +00:00
|
|
|
|
e = new_binary_expr ('.', e1, e2);
|
2011-03-08 10:28:11 +00:00
|
|
|
|
e->e.expr.type = field->type;
|
2011-02-06 23:30:28 +00:00
|
|
|
|
return e;
|
2011-03-08 10:28:11 +00:00
|
|
|
|
} else {
|
|
|
|
|
t2 = get_type (e2);
|
|
|
|
|
if (e2->type == ex_error)
|
|
|
|
|
return e2;
|
|
|
|
|
if (t2->type == ev_field) {
|
|
|
|
|
e = new_binary_expr ('.', e1, e2);
|
|
|
|
|
e->e.expr.type = t2->t.fldptr.type;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
2011-02-06 23:30:28 +00:00
|
|
|
|
}
|
2022-01-25 03:46:14 +00:00
|
|
|
|
} else if (is_ptr (t1)) {
|
2011-02-06 23:30:28 +00:00
|
|
|
|
if (is_struct (t1->t.fldptr.type)) {
|
2011-02-07 13:15:10 +00:00
|
|
|
|
symbol_t *field;
|
2011-02-13 11:23:08 +00:00
|
|
|
|
|
2011-03-07 01:01:21 +00:00
|
|
|
|
field = get_struct_field (t1->t.fldptr.type, e1, e2);
|
2011-02-07 13:15:10 +00:00
|
|
|
|
if (!field)
|
2011-03-07 01:01:21 +00:00
|
|
|
|
return e1;
|
|
|
|
|
|
2022-01-28 00:17:10 +00:00
|
|
|
|
expr_t *offset = new_short_expr (field->s.offset);
|
|
|
|
|
e1 = offset_pointer_expr (e1, offset);
|
|
|
|
|
e1 = cast_expr (pointer_type (field->type), e1);
|
|
|
|
|
return unary_expr ('.', e1);
|
2020-03-27 06:16:41 +00:00
|
|
|
|
} else if (is_class (t1->t.fldptr.type)) {
|
2011-02-06 23:30:28 +00:00
|
|
|
|
class_t *class = t1->t.fldptr.type->t.class;
|
|
|
|
|
symbol_t *sym = e2->e.symbol;//FIXME need to check
|
|
|
|
|
symbol_t *ivar;
|
2020-03-03 01:42:05 +00:00
|
|
|
|
int protected = class_access (current_class, class);
|
2012-05-21 23:23:22 +00:00
|
|
|
|
|
2020-03-03 01:42:05 +00:00
|
|
|
|
ivar = class_find_ivar (class, protected, sym->name);
|
2011-02-06 23:30:28 +00:00
|
|
|
|
if (!ivar)
|
|
|
|
|
return new_error_expr ();
|
2022-01-25 14:39:17 +00:00
|
|
|
|
expr_t *offset = new_short_expr (ivar->s.offset);
|
|
|
|
|
e1 = offset_pointer_expr (e1, offset);
|
|
|
|
|
e1 = cast_expr (pointer_type (ivar->type), e1);
|
|
|
|
|
return unary_expr ('.', e1);
|
2011-02-06 23:30:28 +00:00
|
|
|
|
}
|
2022-04-29 02:31:45 +00:00
|
|
|
|
} else if (is_nonscalar (t1) || is_struct (t1)) {
|
2011-02-08 05:48:26 +00:00
|
|
|
|
symbol_t *field;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
|
2011-03-07 01:01:21 +00:00
|
|
|
|
field = get_struct_field (t1, e1, e2);
|
2011-02-08 05:48:26 +00:00
|
|
|
|
if (!field)
|
2011-03-07 01:01:21 +00:00
|
|
|
|
return e1;
|
|
|
|
|
|
2011-03-06 06:39:27 +00:00
|
|
|
|
if (e1->type == ex_expr && e1->e.expr.op == '.'
|
2020-03-27 06:16:41 +00:00
|
|
|
|
&& is_entity(get_type (e1->e.expr.e1))) {
|
2011-03-06 06:39:27 +00:00
|
|
|
|
// undo the . expression
|
|
|
|
|
e2 = e1->e.expr.e2;
|
|
|
|
|
e1 = e1->e.expr.e1;
|
|
|
|
|
// offset the field expresion
|
|
|
|
|
if (e2->type == ex_symbol) {
|
|
|
|
|
symbol_t *sym;
|
|
|
|
|
def_t *def;
|
|
|
|
|
sym = symtab_lookup (pr.entity_fields, e2->e.symbol->name);
|
|
|
|
|
if (!sym) {
|
2011-03-07 01:01:21 +00:00
|
|
|
|
internal_error (e2, "failed to find entity field %s",
|
2011-03-06 06:39:27 +00:00
|
|
|
|
e2->e.symbol->name);
|
|
|
|
|
}
|
|
|
|
|
def = sym->s.def;
|
|
|
|
|
e2 = new_field_expr (0, field->type, def);
|
2018-10-12 13:05:17 +00:00
|
|
|
|
} else if (e2->type != ex_value
|
|
|
|
|
|| e2->e.value->lltype != ev_field) {
|
2011-03-06 06:39:27 +00:00
|
|
|
|
internal_error (e2, "unexpected field exression");
|
|
|
|
|
}
|
2012-07-19 00:21:57 +00:00
|
|
|
|
e2->e.value = new_field_val (e2->e.value->v.pointer.val + field->s.offset, field->type, e2->e.value->v.pointer.def);
|
2011-03-06 06:39:27 +00:00
|
|
|
|
// create a new . expression
|
|
|
|
|
return field_expr (e1, e2);
|
|
|
|
|
} else {
|
2019-06-10 14:55:16 +00:00
|
|
|
|
if (e1->type == ex_uexpr && e1->e.expr.op == '.') {
|
2022-01-25 14:39:17 +00:00
|
|
|
|
expr_t *offset = new_short_expr (field->s.offset);
|
|
|
|
|
e1 = offset_pointer_expr (e1->e.expr.e1, offset);
|
|
|
|
|
e1 = cast_expr (pointer_type (field->type), e1);
|
|
|
|
|
return unary_expr ('.', e1);
|
2019-06-10 14:55:16 +00:00
|
|
|
|
} else {
|
|
|
|
|
return new_offset_alias_expr (field->type, e1, field->s.offset);
|
|
|
|
|
}
|
2011-03-06 06:39:27 +00:00
|
|
|
|
}
|
2020-03-27 06:16:41 +00:00
|
|
|
|
} else if (is_class (t1)) {
|
2012-12-22 21:01:20 +00:00
|
|
|
|
//Class instance variables aren't allowed and thus declaring one
|
|
|
|
|
//is treated as an error, so this is a follow-on error.
|
|
|
|
|
return error (e1, "class instance access");
|
2011-02-06 23:30:28 +00:00
|
|
|
|
}
|
2001-12-12 08:39:47 +00:00
|
|
|
|
return type_mismatch (e1, e2, '.');
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-27 08:41:20 +00:00
|
|
|
|
expr_t *
|
2003-10-22 09:14:53 +00:00
|
|
|
|
convert_from_bool (expr_t *e, type_t *type)
|
|
|
|
|
{
|
2003-10-22 16:49:57 +00:00
|
|
|
|
expr_t *zero;
|
|
|
|
|
expr_t *one;
|
|
|
|
|
expr_t *cond;
|
|
|
|
|
|
2020-02-19 12:13:36 +00:00
|
|
|
|
if (is_float (type)) {
|
2003-10-22 16:49:57 +00:00
|
|
|
|
one = new_float_expr (1);
|
|
|
|
|
zero = new_float_expr (0);
|
2022-01-18 04:21:06 +00:00
|
|
|
|
} else if (is_int (type)) {
|
|
|
|
|
one = new_int_expr (1);
|
|
|
|
|
zero = new_int_expr (0);
|
2011-03-02 13:46:55 +00:00
|
|
|
|
} else if (is_enum (type) && enum_as_bool (type, &zero, &one)) {
|
|
|
|
|
// don't need to do anything
|
2022-01-18 04:21:06 +00:00
|
|
|
|
} else if (is_uint (type)) {
|
|
|
|
|
one = new_uint_expr (1);
|
|
|
|
|
zero = new_uint_expr (0);
|
2003-10-22 16:49:57 +00:00
|
|
|
|
} else {
|
|
|
|
|
return error (e, "can't convert from bool value");
|
|
|
|
|
}
|
|
|
|
|
cond = new_expr ();
|
|
|
|
|
*cond = *e;
|
|
|
|
|
cond->next = 0;
|
|
|
|
|
|
|
|
|
|
cond = conditional_expr (cond, one, zero);
|
|
|
|
|
e->type = cond->type;
|
|
|
|
|
e->e = cond->e;
|
2003-10-22 09:14:53 +00:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-27 11:30:07 +00:00
|
|
|
|
expr_t *
|
2002-01-30 22:17:55 +00:00
|
|
|
|
convert_nil (expr_t *e, type_t *t)
|
|
|
|
|
{
|
2020-03-13 08:57:58 +00:00
|
|
|
|
e->e.nil = t;
|
2020-02-27 11:30:07 +00:00
|
|
|
|
return e;
|
2002-01-30 22:17:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 08:55:03 +00:00
|
|
|
|
int
|
2003-03-25 17:18:58 +00:00
|
|
|
|
is_compare (int op)
|
|
|
|
|
{
|
2003-08-05 17:48:16 +00:00
|
|
|
|
if (op == EQ || op == NE || op == LE || op == GE || op == LT || op == GT
|
|
|
|
|
|| op == '>' || op == '<')
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-13 06:26:18 +00:00
|
|
|
|
int
|
2011-01-23 02:12:05 +00:00
|
|
|
|
is_math_op (int op)
|
2010-01-13 06:26:18 +00:00
|
|
|
|
{
|
|
|
|
|
if (op == '*' || op == '/' || op == '+' || op == '-')
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 08:55:03 +00:00
|
|
|
|
int
|
2003-08-05 17:48:16 +00:00
|
|
|
|
is_logic (int op)
|
|
|
|
|
{
|
|
|
|
|
if (op == OR || op == AND)
|
2003-03-25 17:18:58 +00:00
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-27 14:07:38 +00:00
|
|
|
|
int
|
2004-01-31 04:11:45 +00:00
|
|
|
|
has_function_call (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
switch (e->type) {
|
|
|
|
|
case ex_bool:
|
|
|
|
|
return has_function_call (e->e.bool.e);
|
|
|
|
|
case ex_block:
|
|
|
|
|
if (e->e.block.is_call)
|
|
|
|
|
return 1;
|
|
|
|
|
for (e = e->e.block.head; e; e = e->next)
|
|
|
|
|
if (has_function_call (e))
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
case ex_expr:
|
|
|
|
|
return (has_function_call (e->e.expr.e1)
|
|
|
|
|
|| has_function_call (e->e.expr.e2));
|
|
|
|
|
case ex_uexpr:
|
2022-01-09 05:02:16 +00:00
|
|
|
|
return has_function_call (e->e.expr.e1);
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
|
|
|
|
return has_function_call (e->e.alias.expr);
|
2022-01-08 07:52:24 +00:00
|
|
|
|
case ex_address:
|
|
|
|
|
return has_function_call (e->e.address.lvalue);
|
2022-01-08 09:44:29 +00:00
|
|
|
|
case ex_assign:
|
|
|
|
|
return (has_function_call (e->e.assign.dst)
|
|
|
|
|
|| has_function_call (e->e.assign.src));
|
2022-01-09 05:02:16 +00:00
|
|
|
|
case ex_branch:
|
|
|
|
|
if (e->e.branch.type == pr_branch_call) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (e->e.branch.type == pr_branch_jump) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return has_function_call (e->e.branch.test);
|
2022-01-09 07:28:08 +00:00
|
|
|
|
case ex_return:
|
|
|
|
|
return has_function_call (e->e.retrn.ret_val);
|
2022-01-30 01:56:15 +00:00
|
|
|
|
case ex_horizontal:
|
|
|
|
|
return has_function_call (e->e.hop.vec);
|
2022-05-01 01:02:26 +00:00
|
|
|
|
case ex_swizzle:
|
|
|
|
|
return has_function_call (e->e.swizzle.src);
|
2022-08-18 08:46:14 +00:00
|
|
|
|
case ex_extend:
|
|
|
|
|
return has_function_call (e->e.extend.src);
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_error:
|
|
|
|
|
case ex_state:
|
|
|
|
|
case ex_label:
|
|
|
|
|
case ex_labelref:
|
|
|
|
|
case ex_def:
|
|
|
|
|
case ex_symbol:
|
|
|
|
|
case ex_temp:
|
|
|
|
|
case ex_vector:
|
|
|
|
|
case ex_selector:
|
|
|
|
|
case ex_nil:
|
|
|
|
|
case ex_value:
|
|
|
|
|
case ex_compound:
|
|
|
|
|
case ex_memset:
|
2022-01-21 09:47:12 +00:00
|
|
|
|
case ex_adjstk:
|
|
|
|
|
case ex_with:
|
2022-01-24 09:35:16 +00:00
|
|
|
|
case ex_args:
|
2022-01-08 03:06:52 +00:00
|
|
|
|
return 0;
|
|
|
|
|
case ex_count:
|
|
|
|
|
break;
|
2004-01-31 04:11:45 +00:00
|
|
|
|
}
|
2022-01-08 03:06:52 +00:00
|
|
|
|
internal_error (e, "invalid expression type");
|
2004-01-31 04:11:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 04:09:23 +00:00
|
|
|
|
int
|
|
|
|
|
is_function_call (expr_t *e)
|
|
|
|
|
{
|
2022-02-05 09:55:36 +00:00
|
|
|
|
if (e->type != ex_block || !e->e.block.is_call) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
e = e->e.block.result;
|
2022-01-21 04:09:23 +00:00
|
|
|
|
return e->type == ex_branch && e->e.branch.type == pr_branch_call;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-10 16:17:00 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
asx_expr (int op, expr_t *e1, expr_t *e2)
|
|
|
|
|
{
|
2002-05-01 22:08:59 +00:00
|
|
|
|
if (e1->type == ex_error)
|
|
|
|
|
return e1;
|
|
|
|
|
else if (e2->type == ex_error)
|
|
|
|
|
return e2;
|
|
|
|
|
else {
|
|
|
|
|
expr_t *e = new_expr ();
|
|
|
|
|
|
|
|
|
|
*e = *e1;
|
2004-02-08 05:28:30 +00:00
|
|
|
|
e2->paren = 1;
|
2002-05-01 22:08:59 +00:00
|
|
|
|
return assign_expr (e, binary_expr (op, e1, e2));
|
|
|
|
|
}
|
2001-08-10 16:17:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-06-20 07:02:36 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
unary_expr (int op, expr_t *e)
|
|
|
|
|
{
|
2011-01-18 23:41:24 +00:00
|
|
|
|
vec3_t v;
|
|
|
|
|
quat_t q;
|
|
|
|
|
const char *s;
|
2020-02-23 14:41:12 +00:00
|
|
|
|
expr_t *new;
|
2020-03-04 16:45:38 +00:00
|
|
|
|
type_t *t;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
|
2011-02-05 13:32:23 +00:00
|
|
|
|
convert_name (e);
|
2002-06-28 16:38:05 +00:00
|
|
|
|
if (e->type == ex_error)
|
|
|
|
|
return e;
|
2001-06-20 21:18:04 +00:00
|
|
|
|
switch (op) {
|
|
|
|
|
case '-':
|
2011-01-23 02:12:58 +00:00
|
|
|
|
if (!is_math (get_type (e)))
|
2012-05-06 09:43:18 +00:00
|
|
|
|
return error (e, "invalid type for unary -");
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (is_constant (e)) {
|
|
|
|
|
switch (extract_type (e)) {
|
|
|
|
|
case ev_string:
|
|
|
|
|
case ev_entity:
|
|
|
|
|
case ev_field:
|
|
|
|
|
case ev_func:
|
2022-01-18 05:36:06 +00:00
|
|
|
|
case ev_ptr:
|
2011-01-23 02:12:58 +00:00
|
|
|
|
internal_error (e, "type check failed!");
|
2020-02-14 07:38:37 +00:00
|
|
|
|
case ev_double:
|
2020-02-23 14:41:12 +00:00
|
|
|
|
new = new_double_expr (-expr_double (e));
|
|
|
|
|
new->implicit = e->implicit;
|
|
|
|
|
return new;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_float:
|
|
|
|
|
return new_float_expr (-expr_float (e));
|
|
|
|
|
case ev_vector:
|
|
|
|
|
VectorNegate (expr_vector (e), v);
|
|
|
|
|
return new_vector_expr (v);
|
2022-01-18 06:48:43 +00:00
|
|
|
|
case ev_quaternion:
|
2011-01-18 23:41:24 +00:00
|
|
|
|
QuatNegate (expr_vector (e), q);
|
|
|
|
|
return new_vector_expr (q);
|
2022-01-05 13:32:07 +00:00
|
|
|
|
case ev_long:
|
|
|
|
|
case ev_ulong:
|
2022-01-18 13:08:37 +00:00
|
|
|
|
case ev_ushort:
|
2022-01-05 13:32:07 +00:00
|
|
|
|
internal_error (e, "long not implemented");
|
2022-01-18 04:21:06 +00:00
|
|
|
|
case ev_int:
|
|
|
|
|
return new_int_expr (-expr_int (e));
|
|
|
|
|
case ev_uint:
|
|
|
|
|
return new_uint_expr (-expr_uint (e));
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_short:
|
|
|
|
|
return new_short_expr (-expr_short (e));
|
|
|
|
|
case ev_invalid:
|
|
|
|
|
case ev_type_count:
|
|
|
|
|
case ev_void:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
internal_error (e, "weird expression type");
|
|
|
|
|
}
|
2001-06-20 21:18:04 +00:00
|
|
|
|
switch (e->type) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ex_value: // should be handled above
|
2002-05-01 22:08:59 +00:00
|
|
|
|
case ex_error:
|
2001-06-25 22:11:20 +00:00
|
|
|
|
case ex_label:
|
2012-11-03 09:08:32 +00:00
|
|
|
|
case ex_labelref:
|
2004-02-11 01:43:33 +00:00
|
|
|
|
case ex_state:
|
2020-03-11 06:46:57 +00:00
|
|
|
|
case ex_compound:
|
2020-03-11 13:57:20 +00:00
|
|
|
|
case ex_memset:
|
2021-12-24 04:22:01 +00:00
|
|
|
|
case ex_selector:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
case ex_return:
|
2022-01-21 09:47:12 +00:00
|
|
|
|
case ex_adjstk:
|
|
|
|
|
case ex_with:
|
2022-01-24 09:35:16 +00:00
|
|
|
|
case ex_args:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
internal_error (e, "unexpected expression type");
|
2001-06-20 21:18:04 +00:00
|
|
|
|
case ex_uexpr:
|
2020-04-08 12:23:57 +00:00
|
|
|
|
if (e->e.expr.op == '-') {
|
2001-06-20 21:18:04 +00:00
|
|
|
|
return e->e.expr.e1;
|
2020-04-08 12:23:57 +00:00
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
|
|
|
|
|
n->e.expr.type = get_type (e);
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_block:
|
2020-04-08 12:23:57 +00:00
|
|
|
|
if (!e->e.block.result) {
|
2001-08-11 21:15:24 +00:00
|
|
|
|
return error (e, "invalid type for unary -");
|
2020-04-08 12:23:57 +00:00
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
|
|
|
|
|
n->e.expr.type = get_type (e);
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2022-01-09 05:02:16 +00:00
|
|
|
|
case ex_branch:
|
|
|
|
|
return error (e, "invalid type for unary -");
|
2001-06-20 21:18:04 +00:00
|
|
|
|
case ex_expr:
|
2003-10-22 08:05:17 +00:00
|
|
|
|
case ex_bool:
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_temp:
|
2013-06-24 06:37:08 +00:00
|
|
|
|
case ex_vector:
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
2022-01-08 09:44:29 +00:00
|
|
|
|
case ex_assign:
|
2022-01-30 01:56:15 +00:00
|
|
|
|
case ex_horizontal:
|
2022-05-01 01:02:26 +00:00
|
|
|
|
case ex_swizzle:
|
2022-08-18 08:46:14 +00:00
|
|
|
|
case ex_extend:
|
2001-06-20 21:18:04 +00:00
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
|
2020-04-08 12:23:57 +00:00
|
|
|
|
n->e.expr.type = get_type (e);
|
2001-06-20 21:18:04 +00:00
|
|
|
|
return n;
|
|
|
|
|
}
|
2020-03-16 16:42:46 +00:00
|
|
|
|
case ex_def:
|
|
|
|
|
{
|
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
|
|
|
|
|
n->e.expr.type = e->e.def->type;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2011-01-13 05:54:24 +00:00
|
|
|
|
case ex_symbol:
|
|
|
|
|
{
|
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
|
|
|
|
|
n->e.expr.type = e->e.symbol->type;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2001-10-17 07:45:37 +00:00
|
|
|
|
case ex_nil:
|
2022-01-08 07:52:24 +00:00
|
|
|
|
case ex_address:
|
2001-06-28 21:26:40 +00:00
|
|
|
|
return error (e, "invalid type for unary -");
|
2021-06-27 05:53:08 +00:00
|
|
|
|
case ex_count:
|
|
|
|
|
internal_error (e, "invalid expression");
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '!':
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (is_constant (e)) {
|
|
|
|
|
switch (extract_type (e)) {
|
|
|
|
|
case ev_entity:
|
|
|
|
|
case ev_field:
|
|
|
|
|
case ev_func:
|
2022-01-18 05:36:06 +00:00
|
|
|
|
case ev_ptr:
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, 0);
|
|
|
|
|
case ev_string:
|
|
|
|
|
s = expr_string (e);
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return new_int_expr (!s || !s[0]);
|
2020-02-14 07:38:37 +00:00
|
|
|
|
case ev_double:
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return new_int_expr (!expr_double (e));
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_float:
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return new_int_expr (!expr_float (e));
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_vector:
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return new_int_expr (!VectorIsZero (expr_vector (e)));
|
2022-01-18 06:48:43 +00:00
|
|
|
|
case ev_quaternion:
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return new_int_expr (!QuatIsZero (expr_quaternion (e)));
|
2022-01-05 13:32:07 +00:00
|
|
|
|
case ev_long:
|
|
|
|
|
case ev_ulong:
|
2022-01-18 13:08:37 +00:00
|
|
|
|
case ev_ushort:
|
2022-01-05 13:32:07 +00:00
|
|
|
|
internal_error (e, "long not implemented");
|
2022-01-18 04:21:06 +00:00
|
|
|
|
case ev_int:
|
|
|
|
|
return new_int_expr (!expr_int (e));
|
|
|
|
|
case ev_uint:
|
|
|
|
|
return new_uint_expr (!expr_uint (e));
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_short:
|
|
|
|
|
return new_short_expr (!expr_short (e));
|
|
|
|
|
case ev_invalid:
|
|
|
|
|
case ev_type_count:
|
|
|
|
|
case ev_void:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
internal_error (e, "weird expression type");
|
|
|
|
|
}
|
2001-06-20 21:18:04 +00:00
|
|
|
|
switch (e->type) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ex_value: // should be handled above
|
2002-05-01 22:08:59 +00:00
|
|
|
|
case ex_error:
|
2001-06-25 22:11:20 +00:00
|
|
|
|
case ex_label:
|
2012-11-03 09:08:32 +00:00
|
|
|
|
case ex_labelref:
|
2004-02-11 01:43:33 +00:00
|
|
|
|
case ex_state:
|
2020-03-11 06:46:57 +00:00
|
|
|
|
case ex_compound:
|
2020-03-11 13:57:20 +00:00
|
|
|
|
case ex_memset:
|
2021-12-24 04:22:01 +00:00
|
|
|
|
case ex_selector:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
case ex_return:
|
2022-01-21 09:47:12 +00:00
|
|
|
|
case ex_adjstk:
|
|
|
|
|
case ex_with:
|
2022-01-24 09:35:16 +00:00
|
|
|
|
case ex_args:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
internal_error (e, "unexpected expression type");
|
2003-10-22 08:05:17 +00:00
|
|
|
|
case ex_bool:
|
|
|
|
|
return new_bool_expr (e->e.bool.false_list,
|
|
|
|
|
e->e.bool.true_list, e);
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_block:
|
|
|
|
|
if (!e->e.block.result)
|
2001-10-06 04:48:52 +00:00
|
|
|
|
return error (e, "invalid type for unary !");
|
2001-06-20 21:18:04 +00:00
|
|
|
|
case ex_uexpr:
|
|
|
|
|
case ex_expr:
|
2020-03-16 16:42:46 +00:00
|
|
|
|
case ex_def:
|
2011-01-13 05:54:24 +00:00
|
|
|
|
case ex_symbol:
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_temp:
|
2013-06-24 06:37:08 +00:00
|
|
|
|
case ex_vector:
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
2022-01-08 07:52:24 +00:00
|
|
|
|
case ex_address:
|
2022-01-08 09:44:29 +00:00
|
|
|
|
case ex_assign:
|
2022-01-30 01:56:15 +00:00
|
|
|
|
case ex_horizontal:
|
2022-05-01 01:02:26 +00:00
|
|
|
|
case ex_swizzle:
|
2022-08-18 08:46:14 +00:00
|
|
|
|
case ex_extend:
|
2022-01-29 09:22:41 +00:00
|
|
|
|
if (options.code.progsversion == PROG_VERSION) {
|
|
|
|
|
return binary_expr (EQ, e, new_nil_expr ());
|
|
|
|
|
} else {
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
|
2001-10-26 06:43:56 +00:00
|
|
|
|
if (options.code.progsversion > PROG_ID_VERSION)
|
2022-01-18 04:21:06 +00:00
|
|
|
|
n->e.expr.type = &type_int;
|
2001-08-03 07:47:15 +00:00
|
|
|
|
else
|
|
|
|
|
n->e.expr.type = &type_float;
|
2001-06-20 21:18:04 +00:00
|
|
|
|
return n;
|
|
|
|
|
}
|
2022-01-09 05:02:16 +00:00
|
|
|
|
case ex_branch:
|
2001-10-17 07:45:37 +00:00
|
|
|
|
case ex_nil:
|
|
|
|
|
return error (e, "invalid type for unary !");
|
2021-06-27 05:53:08 +00:00
|
|
|
|
case ex_count:
|
|
|
|
|
internal_error (e, "invalid expression");
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2001-08-09 16:34:46 +00:00
|
|
|
|
case '~':
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (is_constant (e)) {
|
|
|
|
|
switch (extract_type (e)) {
|
|
|
|
|
case ev_string:
|
|
|
|
|
case ev_entity:
|
|
|
|
|
case ev_field:
|
|
|
|
|
case ev_func:
|
2022-01-18 05:36:06 +00:00
|
|
|
|
case ev_ptr:
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_vector:
|
2020-02-14 07:38:37 +00:00
|
|
|
|
case ev_double:
|
2012-05-06 09:43:18 +00:00
|
|
|
|
return error (e, "invalid type for unary ~");
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_float:
|
|
|
|
|
return new_float_expr (~(int) expr_float (e));
|
2022-01-18 06:48:43 +00:00
|
|
|
|
case ev_quaternion:
|
2011-01-18 23:41:24 +00:00
|
|
|
|
QuatConj (expr_vector (e), q);
|
|
|
|
|
return new_vector_expr (q);
|
2022-01-05 13:32:07 +00:00
|
|
|
|
case ev_long:
|
|
|
|
|
case ev_ulong:
|
2022-01-18 13:08:37 +00:00
|
|
|
|
case ev_ushort:
|
2022-01-05 13:32:07 +00:00
|
|
|
|
internal_error (e, "long not implemented");
|
2022-01-18 04:21:06 +00:00
|
|
|
|
case ev_int:
|
|
|
|
|
return new_int_expr (~expr_int (e));
|
|
|
|
|
case ev_uint:
|
|
|
|
|
return new_uint_expr (~expr_uint (e));
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_short:
|
|
|
|
|
return new_short_expr (~expr_short (e));
|
|
|
|
|
case ev_invalid:
|
2020-03-04 16:45:38 +00:00
|
|
|
|
t = get_type (e);
|
|
|
|
|
if (t->meta == ty_enum) {
|
2022-01-18 04:21:06 +00:00
|
|
|
|
return new_int_expr (~expr_int (e));
|
2020-03-04 16:45:38 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ev_type_count:
|
|
|
|
|
case ev_void:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
internal_error (e, "weird expression type");
|
|
|
|
|
}
|
2001-08-09 16:34:46 +00:00
|
|
|
|
switch (e->type) {
|
2011-01-18 23:41:24 +00:00
|
|
|
|
case ex_value: // should be handled above
|
2002-05-01 22:08:59 +00:00
|
|
|
|
case ex_error:
|
2001-08-09 16:34:46 +00:00
|
|
|
|
case ex_label:
|
2012-11-03 09:08:32 +00:00
|
|
|
|
case ex_labelref:
|
2004-02-11 01:43:33 +00:00
|
|
|
|
case ex_state:
|
2020-03-11 06:46:57 +00:00
|
|
|
|
case ex_compound:
|
2020-03-11 13:57:20 +00:00
|
|
|
|
case ex_memset:
|
2021-12-24 04:22:01 +00:00
|
|
|
|
case ex_selector:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
case ex_return:
|
2022-01-21 09:47:12 +00:00
|
|
|
|
case ex_adjstk:
|
|
|
|
|
case ex_with:
|
2022-01-24 09:35:16 +00:00
|
|
|
|
case ex_args:
|
2022-01-09 07:28:08 +00:00
|
|
|
|
internal_error (e, "unexpected expression type");
|
2001-08-09 16:34:46 +00:00
|
|
|
|
case ex_uexpr:
|
|
|
|
|
if (e->e.expr.op == '~')
|
|
|
|
|
return e->e.expr.e1;
|
2002-09-04 16:18:52 +00:00
|
|
|
|
goto bitnot_expr;
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_block:
|
|
|
|
|
if (!e->e.block.result)
|
2001-12-08 08:19:48 +00:00
|
|
|
|
return error (e, "invalid type for unary ~");
|
2002-09-04 16:18:52 +00:00
|
|
|
|
goto bitnot_expr;
|
2022-01-09 05:02:16 +00:00
|
|
|
|
case ex_branch:
|
|
|
|
|
return error (e, "invalid type for unary ~");
|
2001-08-09 16:34:46 +00:00
|
|
|
|
case ex_expr:
|
2003-10-22 08:05:17 +00:00
|
|
|
|
case ex_bool:
|
2020-03-16 16:42:46 +00:00
|
|
|
|
case ex_def:
|
2011-01-13 05:54:24 +00:00
|
|
|
|
case ex_symbol:
|
2001-08-11 21:15:24 +00:00
|
|
|
|
case ex_temp:
|
2013-06-24 06:37:08 +00:00
|
|
|
|
case ex_vector:
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
2022-01-08 09:44:29 +00:00
|
|
|
|
case ex_assign:
|
2022-01-30 01:56:15 +00:00
|
|
|
|
case ex_horizontal:
|
2022-05-01 01:02:26 +00:00
|
|
|
|
case ex_swizzle:
|
2022-08-18 08:46:14 +00:00
|
|
|
|
case ex_extend:
|
2002-09-04 16:18:52 +00:00
|
|
|
|
bitnot_expr:
|
|
|
|
|
if (options.code.progsversion == PROG_ID_VERSION) {
|
2022-01-18 04:21:06 +00:00
|
|
|
|
expr_t *n1 = new_int_expr (-1);
|
2002-09-04 16:18:52 +00:00
|
|
|
|
return binary_expr ('-', n1, e);
|
|
|
|
|
} else {
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *n = new_unary_expr (op, e);
|
|
|
|
|
type_t *t = get_type (e);
|
|
|
|
|
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (!is_int(t) && !is_float(t)
|
2020-03-27 06:16:41 +00:00
|
|
|
|
&& !is_quaternion(t))
|
2001-08-09 16:34:46 +00:00
|
|
|
|
return error (e, "invalid type for unary ~");
|
|
|
|
|
n->e.expr.type = t;
|
|
|
|
|
return n;
|
|
|
|
|
}
|
2001-10-17 07:45:37 +00:00
|
|
|
|
case ex_nil:
|
2022-01-08 07:52:24 +00:00
|
|
|
|
case ex_address:
|
2001-08-09 16:34:46 +00:00
|
|
|
|
return error (e, "invalid type for unary ~");
|
2021-06-27 05:53:08 +00:00
|
|
|
|
case ex_count:
|
|
|
|
|
internal_error (e, "invalid expression");
|
2001-08-09 16:34:46 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2001-12-12 08:39:47 +00:00
|
|
|
|
case '.':
|
2022-01-18 05:36:06 +00:00
|
|
|
|
if (extract_type (e) != ev_ptr)
|
2001-12-12 08:39:47 +00:00
|
|
|
|
return error (e, "invalid type for unary .");
|
2001-12-12 21:52:07 +00:00
|
|
|
|
e = new_unary_expr ('.', e);
|
2022-01-08 09:48:54 +00:00
|
|
|
|
e->e.expr.type = get_type (e->e.expr.e1)->t.fldptr.type;
|
2001-12-12 08:39:47 +00:00
|
|
|
|
return e;
|
2011-01-13 05:54:24 +00:00
|
|
|
|
case '+':
|
2011-01-23 02:12:58 +00:00
|
|
|
|
if (!is_math (get_type (e)))
|
|
|
|
|
return error (e, "invalid type for unary +");
|
|
|
|
|
return e;
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (e, 0);
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-11-13 11:50:00 +00:00
|
|
|
|
expr_t *
|
2020-02-19 12:28:32 +00:00
|
|
|
|
build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
2001-06-20 21:18:04 +00:00
|
|
|
|
{
|
2001-08-20 04:56:00 +00:00
|
|
|
|
expr_t *e;
|
2020-03-11 10:42:38 +00:00
|
|
|
|
expr_t *p;
|
2022-01-24 09:35:16 +00:00
|
|
|
|
int arg_count = 0, param_count = 0;
|
2001-08-20 04:56:00 +00:00
|
|
|
|
int i;
|
|
|
|
|
expr_t *args = 0, **a = &args;
|
2022-01-23 05:17:25 +00:00
|
|
|
|
type_t *arg_types[PR_MAX_PARAMS];
|
|
|
|
|
expr_t *arg_exprs[PR_MAX_PARAMS][2];
|
2001-08-24 23:22:02 +00:00
|
|
|
|
int arg_expr_count = 0;
|
2022-01-24 09:35:16 +00:00
|
|
|
|
int emit_args = 0;
|
2020-03-10 16:52:45 +00:00
|
|
|
|
expr_t *assign;
|
2001-08-20 04:56:00 +00:00
|
|
|
|
expr_t *call;
|
2001-08-20 18:23:47 +00:00
|
|
|
|
expr_t *err = 0;
|
2001-06-20 21:18:04 +00:00
|
|
|
|
|
2004-02-04 05:49:54 +00:00
|
|
|
|
for (e = params; e; e = e->next) {
|
2002-05-02 05:03:57 +00:00
|
|
|
|
if (e->type == ex_error)
|
|
|
|
|
return e;
|
2002-05-08 17:33:28 +00:00
|
|
|
|
arg_count++;
|
2002-05-02 05:03:57 +00:00
|
|
|
|
}
|
2002-05-01 22:08:59 +00:00
|
|
|
|
|
2022-01-23 05:17:25 +00:00
|
|
|
|
if (arg_count > PR_MAX_PARAMS) {
|
|
|
|
|
return error (fexpr, "more than %d parameters", PR_MAX_PARAMS);
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
2011-01-09 10:41:24 +00:00
|
|
|
|
if (ftype->t.func.num_params < -1) {
|
|
|
|
|
if (-arg_count > ftype->t.func.num_params + 1) {
|
2002-05-08 17:33:28 +00:00
|
|
|
|
if (!options.traditional)
|
2004-02-04 05:49:54 +00:00
|
|
|
|
return error (fexpr, "too few arguments");
|
2004-02-17 00:39:21 +00:00
|
|
|
|
if (options.warnings.traditional)
|
|
|
|
|
warning (fexpr, "too few arguments");
|
2002-05-08 17:33:28 +00:00
|
|
|
|
}
|
2022-01-24 09:35:16 +00:00
|
|
|
|
param_count = -ftype->t.func.num_params - 1;
|
2011-01-09 10:41:24 +00:00
|
|
|
|
} else if (ftype->t.func.num_params >= 0) {
|
|
|
|
|
if (arg_count > ftype->t.func.num_params) {
|
2004-02-04 05:49:54 +00:00
|
|
|
|
return error (fexpr, "too many arguments");
|
2011-01-09 10:41:24 +00:00
|
|
|
|
} else if (arg_count < ftype->t.func.num_params) {
|
2002-02-18 06:23:59 +00:00
|
|
|
|
if (!options.traditional)
|
2004-02-04 05:49:54 +00:00
|
|
|
|
return error (fexpr, "too few arguments");
|
2004-02-17 00:39:21 +00:00
|
|
|
|
if (options.warnings.traditional)
|
|
|
|
|
warning (fexpr, "too few arguments");
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
2022-01-24 09:35:16 +00:00
|
|
|
|
param_count = ftype->t.func.num_params;
|
2001-08-20 18:23:47 +00:00
|
|
|
|
}
|
2022-02-04 13:00:18 +00:00
|
|
|
|
if (ftype->t.func.num_params < 0) {
|
|
|
|
|
emit_args = !ftype->t.func.no_va_list;
|
|
|
|
|
}
|
2022-01-24 09:35:16 +00:00
|
|
|
|
// params is reversed (a, b, c) -> c, b, a
|
2004-02-04 05:49:54 +00:00
|
|
|
|
for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) {
|
2020-03-11 10:42:38 +00:00
|
|
|
|
type_t *t;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
|
2020-03-11 10:42:38 +00:00
|
|
|
|
if (e->type == ex_compound) {
|
2022-01-24 09:35:16 +00:00
|
|
|
|
if (i < param_count) {
|
2020-03-11 10:42:38 +00:00
|
|
|
|
t = ftype->t.func.param_types[i];
|
|
|
|
|
} else {
|
|
|
|
|
return error (e, "cannot pass compound initializer "
|
|
|
|
|
"through ...");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
t = get_type (e);
|
|
|
|
|
}
|
2020-03-02 13:38:12 +00:00
|
|
|
|
if (!t) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-14 23:39:20 +00:00
|
|
|
|
if (!type_size (t)) {
|
2010-11-17 05:45:35 +00:00
|
|
|
|
err = error (e, "type of formal parameter %d is incomplete",
|
|
|
|
|
i + 1);
|
2022-02-14 23:39:20 +00:00
|
|
|
|
}
|
2022-08-27 08:42:08 +00:00
|
|
|
|
if (!is_array (t) && value_too_large (t)) {
|
2010-11-17 05:45:35 +00:00
|
|
|
|
err = error (e, "formal parameter %d is too large to be passed by"
|
|
|
|
|
" value", i + 1);
|
2022-02-14 23:39:20 +00:00
|
|
|
|
}
|
2022-01-24 09:35:16 +00:00
|
|
|
|
if (i < param_count) {
|
2003-08-20 20:28:28 +00:00
|
|
|
|
if (e->type == ex_nil)
|
2011-01-09 10:41:24 +00:00
|
|
|
|
convert_nil (e, t = ftype->t.func.param_types[i]);
|
2003-10-22 16:49:57 +00:00
|
|
|
|
if (e->type == ex_bool)
|
2011-01-09 10:41:24 +00:00
|
|
|
|
convert_from_bool (e, ftype->t.func.param_types[i]);
|
2003-10-22 16:49:57 +00:00
|
|
|
|
if (e->type == ex_error)
|
2004-02-04 05:49:54 +00:00
|
|
|
|
return e;
|
2011-01-09 10:41:24 +00:00
|
|
|
|
if (!type_assignable (ftype->t.func.param_types[i], t)) {
|
2011-01-19 13:19:26 +00:00
|
|
|
|
err = param_mismatch (e, i + 1, fexpr->e.symbol->name,
|
2011-01-09 10:41:24 +00:00
|
|
|
|
ftype->t.func.param_types[i], t);
|
2002-01-17 08:19:53 +00:00
|
|
|
|
}
|
2011-01-09 10:41:24 +00:00
|
|
|
|
t = ftype->t.func.param_types[i];
|
2001-08-20 18:23:47 +00:00
|
|
|
|
} else {
|
2003-08-22 06:04:31 +00:00
|
|
|
|
if (e->type == ex_nil)
|
2011-01-22 07:41:31 +00:00
|
|
|
|
convert_nil (e, t = type_nil);
|
2003-10-22 16:49:57 +00:00
|
|
|
|
if (e->type == ex_bool)
|
|
|
|
|
convert_from_bool (e, get_type (e));
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (e)
|
2004-02-04 05:49:54 +00:00
|
|
|
|
&& options.code.progsversion == PROG_ID_VERSION)
|
2022-04-28 08:37:56 +00:00
|
|
|
|
e = cast_expr (&type_float, e);
|
2020-03-08 10:13:57 +00:00
|
|
|
|
if (options.code.promote_float) {
|
2022-04-29 11:49:18 +00:00
|
|
|
|
if (is_scalar (get_type (e)) && is_float (get_type (e))) {
|
2020-03-08 10:13:57 +00:00
|
|
|
|
t = &type_double;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-04-29 11:49:18 +00:00
|
|
|
|
if (is_scalar (get_type (e)) && is_double (get_type (e))) {
|
2020-03-08 10:13:57 +00:00
|
|
|
|
if (!e->implicit) {
|
|
|
|
|
warning (e, "passing double into ... function");
|
|
|
|
|
}
|
|
|
|
|
if (is_constant (e)) {
|
|
|
|
|
// don't auto-demote non-constant doubles
|
|
|
|
|
t = &type_float;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-14 09:15:34 +00:00
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (e) && options.warnings.vararg_integer)
|
|
|
|
|
warning (e, "passing int constant into ... function");
|
2001-07-23 01:56:49 +00:00
|
|
|
|
}
|
2002-05-08 17:33:28 +00:00
|
|
|
|
arg_types[arg_count - 1 - i] = t;
|
2001-06-20 21:18:04 +00:00
|
|
|
|
}
|
2001-08-20 18:23:47 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2001-08-20 04:56:00 +00:00
|
|
|
|
|
2020-03-10 16:52:45 +00:00
|
|
|
|
call = expr_file_line (new_block_expr (), fexpr);
|
2001-08-24 21:47:52 +00:00
|
|
|
|
call->e.block.is_call = 1;
|
2022-01-24 09:35:16 +00:00
|
|
|
|
// args is built in reverse order so it matches params
|
2020-03-11 10:42:38 +00:00
|
|
|
|
for (p = params, i = 0; p; p = p->next, i++) {
|
2022-01-24 09:35:16 +00:00
|
|
|
|
if (emit_args && arg_count - i == param_count) {
|
|
|
|
|
emit_args = 0;
|
|
|
|
|
*a = new_args_expr ();
|
|
|
|
|
a = &(*a)->next;
|
|
|
|
|
}
|
2020-03-11 10:42:38 +00:00
|
|
|
|
expr_t *e = p;
|
|
|
|
|
if (e->type == ex_compound) {
|
|
|
|
|
e = expr_file_line (initialized_temp_expr (arg_types[i], e), e);
|
|
|
|
|
}
|
2020-03-13 16:24:13 +00:00
|
|
|
|
// FIXME this is target-specific info and should not be in the
|
|
|
|
|
// expression tree
|
|
|
|
|
// That, or always use a temp, since it should get optimized out
|
2004-02-04 04:49:46 +00:00
|
|
|
|
if (has_function_call (e)) {
|
2022-04-27 12:45:05 +00:00
|
|
|
|
expr_t *cast = cast_expr (arg_types[i], e);
|
2020-03-10 16:52:45 +00:00
|
|
|
|
expr_t *tmp = new_temp_def_expr (arg_types[i]);
|
|
|
|
|
*a = expr_file_line (tmp, e);
|
|
|
|
|
arg_exprs[arg_expr_count][0] = expr_file_line (cast, e);
|
2001-08-24 23:22:02 +00:00
|
|
|
|
arg_exprs[arg_expr_count][1] = *a;
|
|
|
|
|
arg_expr_count++;
|
2001-08-24 05:40:48 +00:00
|
|
|
|
} else {
|
2022-04-27 12:45:05 +00:00
|
|
|
|
*a = expr_file_line (cast_expr (arg_types[i], e), e);
|
2001-08-24 21:57:07 +00:00
|
|
|
|
}
|
|
|
|
|
a = &(*a)->next;
|
|
|
|
|
}
|
2022-01-24 09:35:16 +00:00
|
|
|
|
if (emit_args) {
|
|
|
|
|
emit_args = 0;
|
|
|
|
|
*a = new_args_expr ();
|
|
|
|
|
a = &(*a)->next;
|
|
|
|
|
}
|
2001-08-24 23:22:02 +00:00
|
|
|
|
for (i = 0; i < arg_expr_count - 1; i++) {
|
2020-03-10 16:52:45 +00:00
|
|
|
|
assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]);
|
|
|
|
|
append_expr (call, expr_file_line (assign, arg_exprs[i][0]));
|
2001-08-24 23:22:02 +00:00
|
|
|
|
}
|
|
|
|
|
if (arg_expr_count) {
|
2011-01-21 10:07:58 +00:00
|
|
|
|
e = assign_expr (arg_exprs[arg_expr_count - 1][1],
|
|
|
|
|
arg_exprs[arg_expr_count - 1][0]);
|
2020-03-10 16:52:45 +00:00
|
|
|
|
e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]);
|
2001-08-24 23:22:02 +00:00
|
|
|
|
append_expr (call, e);
|
|
|
|
|
}
|
2022-01-09 05:02:16 +00:00
|
|
|
|
e = expr_file_line (call_expr (fexpr, args, ftype->t.func.type), fexpr);
|
2022-01-21 04:09:23 +00:00
|
|
|
|
call->e.block.result = e;
|
2001-08-20 04:56:00 +00:00
|
|
|
|
return call;
|
2001-06-20 07:02:36 +00:00
|
|
|
|
}
|
2001-06-26 07:21:20 +00:00
|
|
|
|
|
2004-02-04 05:49:54 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
function_expr (expr_t *fexpr, expr_t *params)
|
|
|
|
|
{
|
|
|
|
|
type_t *ftype;
|
|
|
|
|
|
2004-11-13 11:50:00 +00:00
|
|
|
|
find_function (fexpr, params);
|
2004-02-04 05:49:54 +00:00
|
|
|
|
ftype = get_type (fexpr);
|
|
|
|
|
|
|
|
|
|
if (fexpr->type == ex_error)
|
|
|
|
|
return fexpr;
|
|
|
|
|
if (ftype->type != ev_func) {
|
2011-01-19 13:19:26 +00:00
|
|
|
|
if (fexpr->type == ex_symbol)
|
2004-02-04 05:49:54 +00:00
|
|
|
|
return error (fexpr, "Called object \"%s\" is not a function",
|
2011-01-19 13:19:26 +00:00
|
|
|
|
fexpr->e.symbol->name);
|
2004-02-04 05:49:54 +00:00
|
|
|
|
else
|
|
|
|
|
return error (fexpr, "Called object is not a function");
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-19 13:19:26 +00:00
|
|
|
|
if (fexpr->type == ex_symbol && params && is_string_val (params)) {
|
2004-02-04 05:49:54 +00:00
|
|
|
|
// FIXME eww, I hate this, but it's needed :(
|
|
|
|
|
// FIXME make a qc hook? :)
|
2011-01-19 13:19:26 +00:00
|
|
|
|
if (strncmp (fexpr->e.symbol->name, "precache_sound", 14) == 0)
|
|
|
|
|
PrecacheSound (expr_string (params), fexpr->e.symbol->name[14]);
|
|
|
|
|
else if (strncmp (fexpr->e.symbol->name, "precache_model", 14) == 0)
|
|
|
|
|
PrecacheModel (expr_string (params), fexpr->e.symbol->name[14]);
|
|
|
|
|
else if (strncmp (fexpr->e.symbol->name, "precache_file", 13) == 0)
|
|
|
|
|
PrecacheFile (expr_string (params), fexpr->e.symbol->name[13]);
|
2004-02-04 05:49:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return build_function_call (fexpr, ftype, params);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-03 06:28:49 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
branch_expr (int op, expr_t *test, expr_t *label)
|
|
|
|
|
{
|
2022-01-09 05:02:16 +00:00
|
|
|
|
// need to translated op due to precedence rules dictating the layout
|
|
|
|
|
// of the token ids
|
|
|
|
|
static pr_branch_e branch_type [] = {
|
|
|
|
|
pr_branch_eq,
|
|
|
|
|
pr_branch_ne,
|
|
|
|
|
pr_branch_lt,
|
|
|
|
|
pr_branch_gt,
|
|
|
|
|
pr_branch_le,
|
|
|
|
|
pr_branch_ge,
|
|
|
|
|
};
|
|
|
|
|
if (op < EQ || op > LE) {
|
|
|
|
|
internal_error (label, "invalid op: %d", op);
|
|
|
|
|
}
|
|
|
|
|
if (label && label->type != ex_label) {
|
2011-03-03 06:28:49 +00:00
|
|
|
|
internal_error (label, "not a label");
|
2022-01-09 05:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
if (label) {
|
2011-03-03 06:28:49 +00:00
|
|
|
|
label->e.label.used++;
|
2022-01-09 05:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
expr_t *branch = new_expr ();
|
|
|
|
|
branch->type = ex_branch;
|
|
|
|
|
branch->e.branch.type = branch_type[op - EQ];
|
|
|
|
|
branch->e.branch.target = label;
|
|
|
|
|
branch->e.branch.test = test;
|
|
|
|
|
return branch;
|
2011-03-03 06:28:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
goto_expr (expr_t *label)
|
|
|
|
|
{
|
2022-01-09 05:02:16 +00:00
|
|
|
|
if (label && label->type != ex_label) {
|
2011-03-03 06:28:49 +00:00
|
|
|
|
internal_error (label, "not a label");
|
2022-01-09 05:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
if (label) {
|
2011-03-03 06:28:49 +00:00
|
|
|
|
label->e.label.used++;
|
2022-01-09 05:02:16 +00:00
|
|
|
|
}
|
|
|
|
|
expr_t *branch = new_expr ();
|
|
|
|
|
branch->type = ex_branch;
|
|
|
|
|
branch->e.branch.type = pr_branch_jump;
|
|
|
|
|
branch->e.branch.target = label;
|
|
|
|
|
return branch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
jump_table_expr (expr_t *table, expr_t *index)
|
|
|
|
|
{
|
|
|
|
|
expr_t *branch = new_expr ();
|
|
|
|
|
branch->type = ex_branch;
|
|
|
|
|
branch->e.branch.type = pr_branch_jump;
|
|
|
|
|
branch->e.branch.target = table;//FIXME separate? all branch types can
|
|
|
|
|
branch->e.branch.index = index;
|
|
|
|
|
return branch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
call_expr (expr_t *func, expr_t *args, type_t *ret_type)
|
|
|
|
|
{
|
|
|
|
|
expr_t *branch = new_expr ();
|
|
|
|
|
branch->type = ex_branch;
|
|
|
|
|
branch->e.branch.type = pr_branch_call;
|
|
|
|
|
branch->e.branch.target = func;
|
|
|
|
|
branch->e.branch.args = args;
|
|
|
|
|
branch->e.branch.ret_type = ret_type;
|
|
|
|
|
return branch;
|
2011-03-03 06:28:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-07-23 02:27:46 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
return_expr (function_t *f, expr_t *e)
|
|
|
|
|
{
|
2020-03-28 03:10:23 +00:00
|
|
|
|
const type_t *t;
|
2020-03-28 04:38:26 +00:00
|
|
|
|
const type_t *ret_type = unalias_type (f->type->t.func.type);
|
2003-10-22 08:05:17 +00:00
|
|
|
|
|
2001-07-23 02:27:46 +00:00
|
|
|
|
if (!e) {
|
2020-03-27 06:16:41 +00:00
|
|
|
|
if (!is_void(ret_type)) {
|
2002-02-18 06:23:59 +00:00
|
|
|
|
if (options.traditional) {
|
2004-02-17 00:39:21 +00:00
|
|
|
|
if (options.warnings.traditional)
|
|
|
|
|
warning (e,
|
|
|
|
|
"return from non-void function without a value");
|
2018-09-08 13:23:57 +00:00
|
|
|
|
// force a nil return value in case qf code is being generated
|
2002-09-11 16:21:26 +00:00
|
|
|
|
e = new_nil_expr ();
|
2002-02-18 06:23:59 +00:00
|
|
|
|
} else {
|
|
|
|
|
e = error (e, "return from non-void function without a value");
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-08 13:23:57 +00:00
|
|
|
|
// the traditional check above may have set e
|
|
|
|
|
if (!e) {
|
2022-01-09 07:28:08 +00:00
|
|
|
|
return new_return_expr (0);
|
2018-09-08 13:23:57 +00:00
|
|
|
|
}
|
2002-02-18 06:23:59 +00:00
|
|
|
|
}
|
2001-10-02 18:55:52 +00:00
|
|
|
|
|
2020-03-13 00:58:52 +00:00
|
|
|
|
if (e->type == ex_compound) {
|
|
|
|
|
e = expr_file_line (initialized_temp_expr (ret_type, e), e);
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-22 08:30:54 +00:00
|
|
|
|
t = get_type (e);
|
|
|
|
|
|
2021-01-04 05:54:04 +00:00
|
|
|
|
if (!t) {
|
2003-10-22 08:05:17 +00:00
|
|
|
|
return e;
|
2020-03-13 00:58:52 +00:00
|
|
|
|
}
|
2020-03-27 06:16:41 +00:00
|
|
|
|
if (is_void(ret_type)) {
|
2003-10-22 08:05:17 +00:00
|
|
|
|
if (!options.traditional)
|
|
|
|
|
return error (e, "returning a value for a void function");
|
2004-02-17 00:39:21 +00:00
|
|
|
|
if (options.warnings.traditional)
|
|
|
|
|
warning (e, "returning a value for a void function");
|
2003-10-22 08:05:17 +00:00
|
|
|
|
}
|
2020-03-13 00:58:52 +00:00
|
|
|
|
if (e->type == ex_bool) {
|
2020-03-28 03:10:23 +00:00
|
|
|
|
e = convert_from_bool (e, (type_t *) ret_type); //FIXME cast
|
2020-03-13 00:58:52 +00:00
|
|
|
|
}
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_float(ret_type) && is_int_val (e)) {
|
2022-04-28 08:37:56 +00:00
|
|
|
|
e = cast_expr (&type_float, e);
|
2003-10-22 08:05:17 +00:00
|
|
|
|
t = &type_float;
|
|
|
|
|
}
|
2020-03-27 06:16:41 +00:00
|
|
|
|
if (is_void(t)) {
|
2004-02-04 02:30:18 +00:00
|
|
|
|
if (e->type == ex_nil) {
|
2020-03-13 00:58:52 +00:00
|
|
|
|
t = ret_type;
|
2020-03-28 03:10:23 +00:00
|
|
|
|
convert_nil (e, (type_t *) t);//FIXME cast
|
2004-02-04 02:30:18 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (!options.traditional)
|
|
|
|
|
return error (e, "void value not ignored as it ought to be");
|
2004-02-17 00:39:21 +00:00
|
|
|
|
if (options.warnings.traditional)
|
|
|
|
|
warning (e, "void value not ignored as it ought to be");
|
2004-02-04 02:30:18 +00:00
|
|
|
|
//FIXME does anything need to be done here?
|
|
|
|
|
}
|
2003-10-22 08:05:17 +00:00
|
|
|
|
}
|
2020-03-13 00:58:52 +00:00
|
|
|
|
if (!type_assignable (ret_type, t)) {
|
2003-10-22 08:05:17 +00:00
|
|
|
|
if (!options.traditional)
|
2022-04-29 06:27:12 +00:00
|
|
|
|
return error (e, "type mismatch for return value of %s: %s -> %s",
|
|
|
|
|
f->sym->name, get_type_string (t),
|
|
|
|
|
get_type_string (ret_type));
|
2004-02-17 00:39:21 +00:00
|
|
|
|
if (options.warnings.traditional)
|
|
|
|
|
warning (e, "type mismatch for return value of %s",
|
2011-01-18 03:37:12 +00:00
|
|
|
|
f->sym->name);
|
2004-02-06 08:40:28 +00:00
|
|
|
|
} else {
|
2020-03-13 00:58:52 +00:00
|
|
|
|
if (ret_type != t) {
|
2020-03-28 03:10:23 +00:00
|
|
|
|
e = cast_expr ((type_t *) ret_type, e);//FIXME cast
|
2018-10-13 14:32:53 +00:00
|
|
|
|
t = f->sym->type->t.func.type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (e->type == ex_vector) {
|
2019-06-08 04:36:03 +00:00
|
|
|
|
e = assign_expr (new_temp_def_expr (t), e);
|
2001-07-23 02:27:46 +00:00
|
|
|
|
}
|
2019-06-09 10:29:21 +00:00
|
|
|
|
if (e->type == ex_block) {
|
|
|
|
|
e->e.block.result->rvalue = 1;
|
|
|
|
|
}
|
2022-01-09 07:28:08 +00:00
|
|
|
|
return new_return_expr (e);
|
2001-07-23 02:27:46 +00:00
|
|
|
|
}
|
2001-08-11 21:15:24 +00:00
|
|
|
|
|
2022-02-05 09:58:42 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
at_return_expr (function_t *f, expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
const type_t *ret_type = unalias_type (f->type->t.func.type);
|
|
|
|
|
|
|
|
|
|
if (!is_void(ret_type)) {
|
|
|
|
|
return error (e, "use of @return in non-void function");
|
|
|
|
|
}
|
|
|
|
|
if (is_nil (e)) {
|
|
|
|
|
// int or pointer 0 seems reasonable
|
|
|
|
|
return new_return_expr (new_int_expr (0));
|
|
|
|
|
} else if (!is_function_call (e)) {
|
|
|
|
|
return error (e, "@return value not a function");
|
|
|
|
|
}
|
|
|
|
|
expr_t *call_expr = e->e.block.result->e.branch.target;
|
|
|
|
|
const type_t *call_type = get_type (call_expr);
|
|
|
|
|
if (!is_func (call_type) && !call_type->t.func.void_return) {
|
|
|
|
|
return error (e, "@return function not void_return");
|
|
|
|
|
}
|
|
|
|
|
expr_t *ret_expr = new_return_expr (e);
|
|
|
|
|
ret_expr->e.retrn.at_return = 1;
|
|
|
|
|
return ret_expr;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-11 21:15:24 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2)
|
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *block = new_block_expr ();
|
|
|
|
|
type_t *type1 = get_type (e1);
|
|
|
|
|
type_t *type2 = get_type (e2);
|
|
|
|
|
expr_t *tlabel = new_label_expr ();
|
2003-10-22 08:05:17 +00:00
|
|
|
|
expr_t *flabel = new_label_expr ();
|
2001-12-06 19:49:40 +00:00
|
|
|
|
expr_t *elabel = new_label_expr ();
|
2001-08-11 21:15:24 +00:00
|
|
|
|
|
2002-05-01 22:08:59 +00:00
|
|
|
|
if (cond->type == ex_error)
|
|
|
|
|
return cond;
|
|
|
|
|
if (e1->type == ex_error)
|
|
|
|
|
return e1;
|
|
|
|
|
if (e2->type == ex_error)
|
|
|
|
|
return e2;
|
|
|
|
|
|
2003-10-22 08:05:17 +00:00
|
|
|
|
cond = convert_bool (cond, 1);
|
2003-10-24 22:23:56 +00:00
|
|
|
|
if (cond->type == ex_error)
|
|
|
|
|
return cond;
|
2003-10-22 08:05:17 +00:00
|
|
|
|
|
|
|
|
|
backpatch (cond->e.bool.true_list, tlabel);
|
|
|
|
|
backpatch (cond->e.bool.false_list, flabel);
|
|
|
|
|
|
2001-08-11 21:15:24 +00:00
|
|
|
|
block->e.block.result = (type1 == type2) ? new_temp_def_expr (type1) : 0;
|
2003-10-22 08:05:17 +00:00
|
|
|
|
append_expr (block, cond);
|
|
|
|
|
append_expr (cond->e.bool.e, flabel);
|
2001-08-11 21:15:24 +00:00
|
|
|
|
if (block->e.block.result)
|
2001-12-12 08:39:47 +00:00
|
|
|
|
append_expr (block, assign_expr (block->e.block.result, e2));
|
2001-08-11 21:15:24 +00:00
|
|
|
|
else
|
|
|
|
|
append_expr (block, e2);
|
2011-03-03 06:28:49 +00:00
|
|
|
|
append_expr (block, goto_expr (elabel));
|
2001-08-11 21:15:24 +00:00
|
|
|
|
append_expr (block, tlabel);
|
|
|
|
|
if (block->e.block.result)
|
2001-12-12 08:39:47 +00:00
|
|
|
|
append_expr (block, assign_expr (block->e.block.result, e1));
|
2001-08-11 21:15:24 +00:00
|
|
|
|
else
|
|
|
|
|
append_expr (block, e1);
|
|
|
|
|
append_expr (block, elabel);
|
|
|
|
|
return block;
|
|
|
|
|
}
|
2001-08-20 06:22:28 +00:00
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
incop_expr (int op, expr_t *e, int postop)
|
|
|
|
|
{
|
2002-09-11 16:21:26 +00:00
|
|
|
|
expr_t *one;
|
2001-11-14 06:45:31 +00:00
|
|
|
|
|
2002-05-01 22:08:59 +00:00
|
|
|
|
if (e->type == ex_error)
|
|
|
|
|
return e;
|
|
|
|
|
|
2022-01-18 04:21:06 +00:00
|
|
|
|
one = new_int_expr (1); // int constants get auto-cast to float
|
2001-08-20 06:22:28 +00:00
|
|
|
|
if (postop) {
|
2011-01-11 03:07:48 +00:00
|
|
|
|
expr_t *t1, *t2;
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
|
type_t *type = get_type (e);
|
2001-08-20 06:22:28 +00:00
|
|
|
|
expr_t *block = new_block_expr ();
|
2011-01-11 03:07:48 +00:00
|
|
|
|
expr_t *res = new_expr ();
|
|
|
|
|
|
2012-12-23 05:47:29 +00:00
|
|
|
|
if (e->type == ex_error) // get_type failed
|
|
|
|
|
return e;
|
2011-01-11 03:07:48 +00:00
|
|
|
|
t1 = new_temp_def_expr (type);
|
|
|
|
|
t2 = new_temp_def_expr (type);
|
|
|
|
|
append_expr (block, assign_expr (t1, e));
|
|
|
|
|
append_expr (block, assign_expr (t2, binary_expr (op, t1, one)));
|
|
|
|
|
res = copy_expr (e);
|
|
|
|
|
if (res->type == ex_uexpr && res->e.expr.op == '.')
|
2022-01-25 14:39:17 +00:00
|
|
|
|
res = deref_pointer_expr (address_expr (res, 0));
|
2011-01-11 03:07:48 +00:00
|
|
|
|
append_expr (block, assign_expr (res, t2));
|
|
|
|
|
block->e.block.result = t1;
|
2001-08-20 06:22:28 +00:00
|
|
|
|
return block;
|
2011-01-11 03:07:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
return asx_expr (op, e, one);
|
2001-08-20 06:22:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-11-15 00:46:36 +00:00
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
array_expr (expr_t *array, expr_t *index)
|
|
|
|
|
{
|
|
|
|
|
type_t *array_type = get_type (array);
|
|
|
|
|
type_t *index_type = get_type (index);
|
2022-02-03 15:25:31 +00:00
|
|
|
|
type_t *ele_type;
|
2001-11-15 00:46:36 +00:00
|
|
|
|
expr_t *scale;
|
2019-06-09 13:25:55 +00:00
|
|
|
|
expr_t *offset;
|
|
|
|
|
expr_t *base;
|
2022-01-25 14:39:17 +00:00
|
|
|
|
expr_t *ptr;
|
2001-12-12 08:39:47 +00:00
|
|
|
|
expr_t *e;
|
2011-01-18 23:41:24 +00:00
|
|
|
|
int ind = 0;
|
2001-11-15 00:46:36 +00:00
|
|
|
|
|
2002-05-01 22:08:59 +00:00
|
|
|
|
if (array->type == ex_error)
|
|
|
|
|
return array;
|
|
|
|
|
if (index->type == ex_error)
|
|
|
|
|
return index;
|
|
|
|
|
|
2022-02-03 15:25:31 +00:00
|
|
|
|
if (!is_ptr (array_type) && !is_array (array_type)
|
|
|
|
|
&& !is_nonscalar (array_type))
|
2001-11-15 00:46:36 +00:00
|
|
|
|
return error (array, "not an array");
|
2012-11-15 04:39:23 +00:00
|
|
|
|
if (!is_integral (index_type))
|
2001-11-15 00:46:36 +00:00
|
|
|
|
return error (index, "invalid array index type");
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (is_short_val (index))
|
|
|
|
|
ind = expr_short (index);
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (index))
|
|
|
|
|
ind = expr_int (index);
|
2022-01-25 14:39:17 +00:00
|
|
|
|
if (is_array (array_type)
|
|
|
|
|
&& array_type->t.array.size
|
2011-01-18 23:41:24 +00:00
|
|
|
|
&& is_constant (index)
|
|
|
|
|
&& (ind < array_type->t.array.base
|
2022-02-03 15:25:31 +00:00
|
|
|
|
|| ind - array_type->t.array.base >= array_type->t.array.size)) {
|
|
|
|
|
return error (index, "array index out of bounds");
|
|
|
|
|
}
|
|
|
|
|
if (is_nonscalar (array_type)
|
|
|
|
|
&& is_constant (index)
|
|
|
|
|
&& (ind < 0 || ind >= array_type->width)) {
|
|
|
|
|
return error (index, "array index out of bounds");
|
|
|
|
|
}
|
|
|
|
|
if (is_array (array_type)) {
|
|
|
|
|
ele_type = array_type->t.array.type;
|
|
|
|
|
base = new_int_expr (array_type->t.array.base);
|
|
|
|
|
} else if (is_ptr (array_type)) {
|
|
|
|
|
ele_type = array_type->t.fldptr.type;
|
|
|
|
|
base = new_int_expr (0);
|
|
|
|
|
} else {
|
|
|
|
|
ele_type = ev_types[array_type->type];
|
2023-05-16 16:09:31 +00:00
|
|
|
|
if (array->type == ex_uexpr && array->e.expr.op == '.') {
|
|
|
|
|
expr_t *vec = offset_pointer_expr (array->e.expr.e1, index);
|
|
|
|
|
vec = cast_expr (pointer_type (ele_type), vec);
|
|
|
|
|
return unary_expr ('.', vec);
|
|
|
|
|
}
|
2022-02-03 15:25:31 +00:00
|
|
|
|
base = new_int_expr (0);
|
|
|
|
|
}
|
|
|
|
|
scale = new_int_expr (type_size (ele_type));
|
2019-06-09 15:36:13 +00:00
|
|
|
|
index = binary_expr ('*', index, scale);
|
|
|
|
|
offset = binary_expr ('*', base, scale);
|
|
|
|
|
index = binary_expr ('-', index, offset);
|
2011-01-18 23:41:24 +00:00
|
|
|
|
if (is_short_val (index))
|
|
|
|
|
ind = expr_short (index);
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (index))
|
|
|
|
|
ind = expr_int (index);
|
2011-01-09 10:41:24 +00:00
|
|
|
|
if (is_array (array_type)) {
|
2022-01-25 14:39:17 +00:00
|
|
|
|
if (array->type == ex_uexpr && array->e.expr.op == '.') {
|
|
|
|
|
ptr = array->e.expr.e1;
|
2003-05-13 19:49:23 +00:00
|
|
|
|
} else {
|
2022-02-03 15:25:31 +00:00
|
|
|
|
expr_t *alias = new_offset_alias_expr (ele_type, array, 0);
|
|
|
|
|
ptr = new_address_expr (ele_type, alias, 0);
|
2003-05-13 19:49:23 +00:00
|
|
|
|
}
|
2022-02-03 15:25:31 +00:00
|
|
|
|
} else if (is_nonscalar (array_type)) {
|
|
|
|
|
expr_t *alias = new_offset_alias_expr (ele_type, array, 0);
|
|
|
|
|
ptr = new_address_expr (ele_type, alias, 0);
|
2022-01-25 14:39:17 +00:00
|
|
|
|
} else {
|
|
|
|
|
ptr = array;
|
2002-06-12 22:37:18 +00:00
|
|
|
|
}
|
2022-01-25 14:39:17 +00:00
|
|
|
|
ptr = offset_pointer_expr (ptr, index);
|
2022-02-03 15:25:31 +00:00
|
|
|
|
ptr = cast_expr (pointer_type (ele_type), ptr);
|
2022-01-25 14:39:17 +00:00
|
|
|
|
|
|
|
|
|
e = unary_expr ('.', ptr);
|
2002-06-12 22:37:18 +00:00
|
|
|
|
return e;
|
2001-12-12 08:39:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-01-13 06:31:41 +00:00
|
|
|
|
expr_t *
|
2022-01-25 03:28:53 +00:00
|
|
|
|
deref_pointer_expr (expr_t *pointer)
|
2010-01-13 06:31:41 +00:00
|
|
|
|
{
|
|
|
|
|
type_t *pointer_type = get_type (pointer);
|
|
|
|
|
|
2010-01-13 06:32:10 +00:00
|
|
|
|
if (pointer->type == ex_error)
|
|
|
|
|
return pointer;
|
2022-01-18 05:36:06 +00:00
|
|
|
|
if (pointer_type->type != ev_ptr)
|
2010-01-13 06:31:41 +00:00
|
|
|
|
return error (pointer, "not a pointer");
|
2022-01-28 06:26:47 +00:00
|
|
|
|
return unary_expr ('.', pointer);
|
2010-01-13 06:31:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-12-12 08:39:47 +00:00
|
|
|
|
expr_t *
|
2022-01-25 14:39:17 +00:00
|
|
|
|
offset_pointer_expr (expr_t *pointer, expr_t *offset)
|
|
|
|
|
{
|
|
|
|
|
type_t *ptr_type = get_type (pointer);
|
|
|
|
|
if (!is_ptr (ptr_type)) {
|
|
|
|
|
internal_error (pointer, "not a pointer");
|
|
|
|
|
}
|
|
|
|
|
if (!is_integral (get_type (offset))) {
|
|
|
|
|
internal_error (offset, "pointer offset is not an integer type");
|
|
|
|
|
}
|
|
|
|
|
expr_t *ptr;
|
|
|
|
|
if (pointer->type == ex_alias && !pointer->e.alias.offset
|
|
|
|
|
&& is_integral (get_type (pointer->e.alias.expr))) {
|
|
|
|
|
ptr = pointer->e.alias.expr;
|
2022-02-03 01:55:37 +00:00
|
|
|
|
} else if (pointer->type == ex_address && is_constant (offset)) {
|
|
|
|
|
if (pointer->e.address.offset) {
|
|
|
|
|
offset = binary_expr ('+', pointer->e.address.offset, offset);
|
|
|
|
|
}
|
|
|
|
|
pointer->e.address.offset = offset;
|
|
|
|
|
return pointer;
|
2022-01-25 14:39:17 +00:00
|
|
|
|
} else {
|
|
|
|
|
ptr = cast_expr (&type_int, pointer);
|
|
|
|
|
}
|
|
|
|
|
ptr = binary_expr ('+', ptr, offset);
|
|
|
|
|
return cast_expr (ptr_type, ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
address_expr (expr_t *e1, type_t *t)
|
2001-12-12 08:39:47 +00:00
|
|
|
|
{
|
|
|
|
|
expr_t *e;
|
|
|
|
|
|
2002-05-01 22:08:59 +00:00
|
|
|
|
if (e1->type == ex_error)
|
|
|
|
|
return e1;
|
|
|
|
|
|
2001-12-12 08:39:47 +00:00
|
|
|
|
if (!t)
|
|
|
|
|
t = get_type (e1);
|
|
|
|
|
|
|
|
|
|
switch (e1->type) {
|
2020-03-17 03:13:09 +00:00
|
|
|
|
case ex_def:
|
|
|
|
|
{
|
|
|
|
|
def_t *def = e1->e.def;
|
|
|
|
|
type_t *type = def->type;
|
|
|
|
|
|
2022-01-25 14:39:17 +00:00
|
|
|
|
//FIXME this test should be in statements.c
|
|
|
|
|
if (options.code.progsversion == PROG_VERSION
|
|
|
|
|
&& (def->local || def->param)) {
|
|
|
|
|
e = new_address_expr (t, e1, 0);
|
|
|
|
|
return e;
|
|
|
|
|
}
|
2020-03-17 03:13:09 +00:00
|
|
|
|
if (is_array (type)) {
|
|
|
|
|
e = e1;
|
|
|
|
|
e->type = ex_value;
|
|
|
|
|
e->e.value = new_pointer_val (0, t, def, 0);
|
|
|
|
|
} else {
|
|
|
|
|
e = new_pointer_expr (0, t, def);
|
|
|
|
|
e->line = e1->line;
|
|
|
|
|
e->file = e1->file;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2011-01-19 13:19:26 +00:00
|
|
|
|
case ex_symbol:
|
|
|
|
|
if (e1->e.symbol->sy_type == sy_var) {
|
2011-02-04 14:20:37 +00:00
|
|
|
|
def_t *def = e1->e.symbol->s.def;
|
|
|
|
|
type_t *type = def->type;
|
|
|
|
|
|
2022-01-25 14:39:17 +00:00
|
|
|
|
//FIXME this test should be in statements.c
|
|
|
|
|
if (options.code.progsversion == PROG_VERSION
|
|
|
|
|
&& (def->local || def->param)) {
|
|
|
|
|
e = new_address_expr (t, e1, 0);
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-07 00:58:51 +00:00
|
|
|
|
if (is_array (type)) {
|
2011-02-04 14:20:37 +00:00
|
|
|
|
e = e1;
|
|
|
|
|
e->type = ex_value;
|
2020-03-16 03:15:55 +00:00
|
|
|
|
e->e.value = new_pointer_val (0, t, def, 0);
|
2011-02-04 14:20:37 +00:00
|
|
|
|
} else {
|
2011-03-07 00:58:51 +00:00
|
|
|
|
e = new_pointer_expr (0, t, def);
|
|
|
|
|
e->line = e1->line;
|
|
|
|
|
e->file = e1->file;
|
2011-02-04 14:20:37 +00:00
|
|
|
|
}
|
2002-07-14 03:41:13 +00:00
|
|
|
|
break;
|
2001-12-12 08:39:47 +00:00
|
|
|
|
}
|
2011-01-19 13:19:26 +00:00
|
|
|
|
return error (e1, "invalid type for unary &");
|
2001-12-12 08:39:47 +00:00
|
|
|
|
case ex_expr:
|
|
|
|
|
if (e1->e.expr.op == '.') {
|
2022-01-08 07:52:24 +00:00
|
|
|
|
e = new_address_expr (e1->e.expr.type,
|
|
|
|
|
e1->e.expr.e1, e1->e.expr.e2);
|
2001-12-12 18:34:41 +00:00
|
|
|
|
break;
|
2001-12-12 08:39:47 +00:00
|
|
|
|
}
|
2001-12-12 18:34:41 +00:00
|
|
|
|
return error (e1, "invalid type for unary &");
|
2001-12-12 08:39:47 +00:00
|
|
|
|
case ex_uexpr:
|
|
|
|
|
if (e1->e.expr.op == '.') {
|
|
|
|
|
e = e1->e.expr.e1;
|
|
|
|
|
if (e->type == ex_expr && e->e.expr.op == '.') {
|
2022-01-08 07:52:24 +00:00
|
|
|
|
e = new_address_expr (e->e.expr.type, e->e.expr.e1, e->e.expr.e2);
|
2001-12-12 08:39:47 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-12-13 16:40:46 +00:00
|
|
|
|
return error (e1, "invalid type for unary &");
|
2012-11-03 09:08:32 +00:00
|
|
|
|
case ex_label:
|
|
|
|
|
return new_label_ref (&e1->e.label);
|
2019-06-08 04:35:47 +00:00
|
|
|
|
case ex_temp:
|
2022-01-08 07:52:24 +00:00
|
|
|
|
e = new_address_expr (t, e1, 0);
|
2019-06-08 04:35:47 +00:00
|
|
|
|
break;
|
2022-01-08 03:06:52 +00:00
|
|
|
|
case ex_alias:
|
|
|
|
|
if (!t) {
|
|
|
|
|
t = e1->e.alias.type;
|
|
|
|
|
}
|
2022-01-25 14:39:17 +00:00
|
|
|
|
return new_address_expr (t, e1, 0);
|
2001-12-12 08:39:47 +00:00
|
|
|
|
default:
|
2001-12-13 16:40:46 +00:00
|
|
|
|
return error (e1, "invalid type for unary &");
|
2001-12-12 08:39:47 +00:00
|
|
|
|
}
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-13 05:33:16 +00:00
|
|
|
|
expr_t *
|
2012-12-20 01:02:00 +00:00
|
|
|
|
build_if_statement (int not, expr_t *test, expr_t *s1, expr_t *els, expr_t *s2)
|
2011-01-13 05:33:16 +00:00
|
|
|
|
{
|
|
|
|
|
int line = pr.source_line;
|
2022-01-18 03:11:14 +00:00
|
|
|
|
pr_string_t file = pr.source_file;
|
2011-01-13 05:33:16 +00:00
|
|
|
|
expr_t *if_expr;
|
|
|
|
|
expr_t *tl = new_label_expr ();
|
|
|
|
|
expr_t *fl = new_label_expr ();
|
|
|
|
|
|
2013-09-30 09:09:04 +00:00
|
|
|
|
if (els && !s2) {
|
|
|
|
|
warning (els,
|
|
|
|
|
"suggest braces around empty body in an ‘else’ statement");
|
|
|
|
|
}
|
|
|
|
|
if (!els && !s1) {
|
|
|
|
|
warning (test,
|
|
|
|
|
"suggest braces around empty body in an ‘if’ statement");
|
|
|
|
|
}
|
2011-01-13 05:33:16 +00:00
|
|
|
|
pr.source_line = test->line;
|
|
|
|
|
pr.source_file = test->file;
|
|
|
|
|
|
|
|
|
|
if_expr = new_block_expr ();
|
|
|
|
|
|
|
|
|
|
test = convert_bool (test, 1);
|
|
|
|
|
if (test->type != ex_error) {
|
2012-12-20 01:02:00 +00:00
|
|
|
|
if (not) {
|
|
|
|
|
backpatch (test->e.bool.true_list, fl);
|
|
|
|
|
backpatch (test->e.bool.false_list, tl);
|
|
|
|
|
} else {
|
|
|
|
|
backpatch (test->e.bool.true_list, tl);
|
|
|
|
|
backpatch (test->e.bool.false_list, fl);
|
|
|
|
|
}
|
2011-01-13 05:33:16 +00:00
|
|
|
|
append_expr (test->e.bool.e, tl);
|
|
|
|
|
append_expr (if_expr, test);
|
|
|
|
|
}
|
|
|
|
|
append_expr (if_expr, s1);
|
|
|
|
|
|
2012-12-01 07:37:38 +00:00
|
|
|
|
if (els) {
|
|
|
|
|
pr.source_line = els->line;
|
|
|
|
|
pr.source_file = els->file;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-13 05:33:16 +00:00
|
|
|
|
if (s2) {
|
|
|
|
|
expr_t *nl = new_label_expr ();
|
2011-03-03 06:28:49 +00:00
|
|
|
|
append_expr (if_expr, goto_expr (nl));
|
2011-01-13 05:33:16 +00:00
|
|
|
|
|
|
|
|
|
append_expr (if_expr, fl);
|
|
|
|
|
append_expr (if_expr, s2);
|
|
|
|
|
append_expr (if_expr, nl);
|
|
|
|
|
} else {
|
|
|
|
|
append_expr (if_expr, fl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pr.source_line = line;
|
|
|
|
|
pr.source_file = file;
|
|
|
|
|
|
|
|
|
|
return if_expr;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-17 13:33:33 +00:00
|
|
|
|
expr_t *
|
2013-06-25 01:46:51 +00:00
|
|
|
|
build_while_statement (int not, expr_t *test, expr_t *statement,
|
2011-01-17 13:33:33 +00:00
|
|
|
|
expr_t *break_label, expr_t *continue_label)
|
|
|
|
|
{
|
|
|
|
|
int line = pr.source_line;
|
2022-01-18 03:11:14 +00:00
|
|
|
|
pr_string_t file = pr.source_file;
|
2011-01-17 13:33:33 +00:00
|
|
|
|
expr_t *l1 = new_label_expr ();
|
|
|
|
|
expr_t *l2 = break_label;
|
|
|
|
|
expr_t *while_expr;
|
|
|
|
|
|
|
|
|
|
pr.source_line = test->line;
|
|
|
|
|
pr.source_file = test->file;
|
|
|
|
|
|
|
|
|
|
while_expr = new_block_expr ();
|
|
|
|
|
|
2011-03-03 06:28:49 +00:00
|
|
|
|
append_expr (while_expr, goto_expr (continue_label));
|
2011-01-17 13:33:33 +00:00
|
|
|
|
append_expr (while_expr, l1);
|
|
|
|
|
append_expr (while_expr, statement);
|
|
|
|
|
append_expr (while_expr, continue_label);
|
|
|
|
|
|
|
|
|
|
test = convert_bool (test, 1);
|
|
|
|
|
if (test->type != ex_error) {
|
2013-06-25 01:46:51 +00:00
|
|
|
|
if (not) {
|
|
|
|
|
backpatch (test->e.bool.true_list, l2);
|
|
|
|
|
backpatch (test->e.bool.false_list, l1);
|
|
|
|
|
} else {
|
|
|
|
|
backpatch (test->e.bool.true_list, l1);
|
|
|
|
|
backpatch (test->e.bool.false_list, l2);
|
|
|
|
|
}
|
2011-01-17 13:33:33 +00:00
|
|
|
|
append_expr (test->e.bool.e, l2);
|
|
|
|
|
append_expr (while_expr, test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pr.source_line = line;
|
|
|
|
|
pr.source_file = file;
|
|
|
|
|
|
|
|
|
|
return while_expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
2013-06-25 01:46:51 +00:00
|
|
|
|
build_do_while_statement (expr_t *statement, int not, expr_t *test,
|
2011-01-17 13:33:33 +00:00
|
|
|
|
expr_t *break_label, expr_t *continue_label)
|
|
|
|
|
{
|
|
|
|
|
expr_t *l1 = new_label_expr ();
|
|
|
|
|
int line = pr.source_line;
|
2022-01-18 03:11:14 +00:00
|
|
|
|
pr_string_t file = pr.source_file;
|
2011-01-17 13:33:33 +00:00
|
|
|
|
expr_t *do_while_expr;
|
|
|
|
|
|
2013-09-30 09:09:04 +00:00
|
|
|
|
if (!statement) {
|
|
|
|
|
warning (break_label,
|
|
|
|
|
"suggest braces around empty body in a ‘do’ statement");
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-17 13:33:33 +00:00
|
|
|
|
pr.source_line = test->line;
|
|
|
|
|
pr.source_file = test->file;
|
|
|
|
|
|
|
|
|
|
do_while_expr = new_block_expr ();
|
|
|
|
|
|
|
|
|
|
append_expr (do_while_expr, l1);
|
|
|
|
|
append_expr (do_while_expr, statement);
|
|
|
|
|
append_expr (do_while_expr, continue_label);
|
|
|
|
|
|
|
|
|
|
test = convert_bool (test, 1);
|
|
|
|
|
if (test->type != ex_error) {
|
2013-06-25 01:46:51 +00:00
|
|
|
|
if (not) {
|
|
|
|
|
backpatch (test->e.bool.true_list, break_label);
|
|
|
|
|
backpatch (test->e.bool.false_list, l1);
|
|
|
|
|
} else {
|
|
|
|
|
backpatch (test->e.bool.true_list, l1);
|
|
|
|
|
backpatch (test->e.bool.false_list, break_label);
|
|
|
|
|
}
|
2011-01-17 13:33:33 +00:00
|
|
|
|
append_expr (test->e.bool.e, break_label);
|
|
|
|
|
append_expr (do_while_expr, test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pr.source_line = line;
|
|
|
|
|
pr.source_file = file;
|
|
|
|
|
|
|
|
|
|
return do_while_expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
build_for_statement (expr_t *init, expr_t *test, expr_t *next,
|
|
|
|
|
expr_t *statement,
|
|
|
|
|
expr_t *break_label, expr_t *continue_label)
|
|
|
|
|
{
|
|
|
|
|
expr_t *tl = new_label_expr ();
|
|
|
|
|
expr_t *fl = break_label;
|
|
|
|
|
expr_t *l1 = 0;
|
|
|
|
|
expr_t *t;
|
|
|
|
|
int line = pr.source_line;
|
2022-01-18 03:11:14 +00:00
|
|
|
|
pr_string_t file = pr.source_file;
|
2011-01-17 13:33:33 +00:00
|
|
|
|
expr_t *for_expr;
|
|
|
|
|
|
|
|
|
|
if (next)
|
|
|
|
|
t = next;
|
|
|
|
|
else if (test)
|
|
|
|
|
t = test;
|
|
|
|
|
else if (init)
|
|
|
|
|
t = init;
|
|
|
|
|
else
|
|
|
|
|
t = continue_label;
|
|
|
|
|
pr.source_line = t->line;
|
|
|
|
|
pr.source_file = t->file;
|
|
|
|
|
|
|
|
|
|
for_expr = new_block_expr ();
|
|
|
|
|
|
|
|
|
|
append_expr (for_expr, init);
|
|
|
|
|
if (test) {
|
|
|
|
|
l1 = new_label_expr ();
|
2011-03-03 06:28:49 +00:00
|
|
|
|
append_expr (for_expr, goto_expr (l1));
|
2011-01-17 13:33:33 +00:00
|
|
|
|
}
|
|
|
|
|
append_expr (for_expr, tl);
|
|
|
|
|
append_expr (for_expr, statement);
|
|
|
|
|
append_expr (for_expr, continue_label);
|
|
|
|
|
append_expr (for_expr, next);
|
|
|
|
|
if (test) {
|
|
|
|
|
append_expr (for_expr, l1);
|
|
|
|
|
test = convert_bool (test, 1);
|
|
|
|
|
if (test->type != ex_error) {
|
|
|
|
|
backpatch (test->e.bool.true_list, tl);
|
|
|
|
|
backpatch (test->e.bool.false_list, fl);
|
|
|
|
|
append_expr (test->e.bool.e, fl);
|
|
|
|
|
append_expr (for_expr, test);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-03-03 06:28:49 +00:00
|
|
|
|
append_expr (for_expr, goto_expr (tl));
|
2011-01-17 13:33:33 +00:00
|
|
|
|
append_expr (for_expr, fl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pr.source_line = line;
|
|
|
|
|
pr.source_file = file;
|
|
|
|
|
|
|
|
|
|
return for_expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expr_t *
|
2013-06-24 02:36:52 +00:00
|
|
|
|
build_state_expr (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
expr_t *frame = 0;
|
|
|
|
|
expr_t *think = 0;
|
|
|
|
|
expr_t *step = 0;
|
|
|
|
|
|
|
|
|
|
e = reverse_expr_list (e);
|
|
|
|
|
frame = e;
|
|
|
|
|
think = frame->next;
|
|
|
|
|
step = think->next;
|
|
|
|
|
if (think->type == ex_symbol)
|
|
|
|
|
think = think_expr (think->e.symbol);
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (frame))
|
2022-04-28 08:37:56 +00:00
|
|
|
|
frame = cast_expr (&type_float, frame);
|
2011-01-17 13:33:33 +00:00
|
|
|
|
if (!type_assignable (&type_float, get_type (frame)))
|
|
|
|
|
return error (frame, "invalid type for frame number");
|
|
|
|
|
if (extract_type (think) != ev_func)
|
|
|
|
|
return error (think, "invalid type for think");
|
|
|
|
|
if (step) {
|
2013-06-24 02:36:52 +00:00
|
|
|
|
if (step->next)
|
|
|
|
|
return error (step->next, "too many state arguments");
|
2022-01-18 04:21:06 +00:00
|
|
|
|
if (is_int_val (step))
|
2022-04-28 08:37:56 +00:00
|
|
|
|
step = cast_expr (&type_float, step);
|
2011-01-17 13:33:33 +00:00
|
|
|
|
if (!type_assignable (&type_float, get_type (step)))
|
2013-06-24 02:36:52 +00:00
|
|
|
|
return error (step, "invalid type for step");
|
2011-01-17 13:33:33 +00:00
|
|
|
|
}
|
|
|
|
|
return new_state_expr (frame, think, step);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-05 09:01:37 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
think_expr (symbol_t *think_sym)
|
|
|
|
|
{
|
|
|
|
|
symbol_t *sym;
|
|
|
|
|
|
|
|
|
|
if (think_sym->table)
|
|
|
|
|
return new_symbol_expr (think_sym);
|
|
|
|
|
|
|
|
|
|
sym = symtab_lookup (current_symtab, "think");
|
|
|
|
|
if (sym && sym->sy_type == sy_var && sym->type
|
|
|
|
|
&& sym->type->type == ev_field
|
|
|
|
|
&& sym->type->t.fldptr.type->type == ev_func) {
|
|
|
|
|
think_sym->type = sym->type->t.fldptr.type;
|
|
|
|
|
} else {
|
2022-01-18 13:34:52 +00:00
|
|
|
|
think_sym->type = &type_func;
|
2011-03-05 09:01:37 +00:00
|
|
|
|
}
|
|
|
|
|
think_sym = function_symbol (think_sym, 0, 1);
|
|
|
|
|
make_function (think_sym, 0, current_symtab->space, current_storage);
|
|
|
|
|
return new_symbol_expr (think_sym);
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-08 23:12:49 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
encode_expr (type_t *type)
|
|
|
|
|
{
|
2002-05-10 23:19:57 +00:00
|
|
|
|
dstring_t *encoding = dstring_newstr ();
|
2002-09-11 16:21:26 +00:00
|
|
|
|
expr_t *e;
|
2002-05-10 23:19:57 +00:00
|
|
|
|
|
|
|
|
|
encode_type (encoding, type);
|
2002-09-11 16:21:26 +00:00
|
|
|
|
e = new_string_expr (encoding->str);
|
2002-05-10 23:19:57 +00:00
|
|
|
|
free (encoding);
|
|
|
|
|
return e;
|
2002-05-08 23:12:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-18 04:08:02 +00:00
|
|
|
|
expr_t *
|
|
|
|
|
sizeof_expr (expr_t *expr, struct type_s *type)
|
|
|
|
|
{
|
2012-10-26 10:02:02 +00:00
|
|
|
|
if (!((!expr) ^ (!type)))
|
2011-01-18 23:41:24 +00:00
|
|
|
|
internal_error (0, 0);
|
2002-08-18 04:08:02 +00:00
|
|
|
|
if (!type)
|
|
|
|
|
type = get_type (expr);
|
2022-01-18 05:36:06 +00:00
|
|
|
|
if (type) {
|
|
|
|
|
expr = new_int_expr (type_size (type));
|
|
|
|
|
}
|
2002-08-18 04:08:02 +00:00
|
|
|
|
return expr;
|
|
|
|
|
}
|
2013-06-24 02:36:52 +00:00
|
|
|
|
|
|
|
|
|
expr_t *
|
|
|
|
|
reverse_expr_list (expr_t *e)
|
|
|
|
|
{
|
|
|
|
|
expr_t *r = 0;
|
|
|
|
|
|
|
|
|
|
while (e) {
|
|
|
|
|
expr_t *t = e->next;
|
|
|
|
|
e->next = r;
|
|
|
|
|
r = e;
|
|
|
|
|
e = t;
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|