int size, align;
void (*init)(struct type *type, struct value *val);
void (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
- void (*print)(struct type *type, struct value *val);
+ void (*print)(struct type *type, struct value *val, FILE *f);
void (*print_type)(struct type *type, FILE *f);
int (*cmp_order)(struct type *t1, struct type *t2,
struct value *v1, struct value *v2);
return -1; // NOTEST
}
- static void print_value(struct type *type, struct value *v)
+ static void print_value(struct type *type, struct value *v, FILE *f)
{
if (type && type->print)
- type->print(type, v);
+ type->print(type, v, f);
else
- printf("*Unknown*"); // NOTEST
+ fprintf(f, "*Unknown*"); // NOTEST
}
###### forward decls
struct value *vold, struct value *vnew);
static int value_cmp(struct type *tl, struct type *tr,
struct value *left, struct value *right);
- static void print_value(struct type *type, struct value *v);
+ static void print_value(struct type *type, struct value *v, FILE *f);
###### free context types
return cmp;
}
- static void _print_value(struct type *type, struct value *v)
+ static void _print_value(struct type *type, struct value *v, FILE *f)
{
switch (type->vtype) {
case Vnone: // NOTEST
- printf("*no-value*"); break; // NOTEST
+ fprintf(f, "*no-value*"); break; // NOTEST
case Vlabel: // NOTEST
- printf("*label-%p*", v->label); break; // NOTEST
+ fprintf(f, "*label-%p*", v->label); break; // NOTEST
case Vstr:
- printf("%.*s", v->str.len, v->str.txt); break;
+ fprintf(f, "%.*s", v->str.len, v->str.txt); break;
case Vbool:
- printf("%s", v->bool ? "True":"False"); break;
+ fprintf(f, "%s", v->bool ? "True":"False"); break;
case Vnum:
{
mpf_t fl;
mpf_init2(fl, 20);
mpf_set_q(fl, v->num);
- gmp_printf("%Fg", fl);
+ gmp_fprintf(f, "%Fg", fl);
mpf_clear(fl);
break;
}
static void scope_finalize(struct parse_context *c, struct type *ft)
{
- int size = 0;
+ int size = ft->function.local_size;
struct variable *next = ft->function.scope;
struct variable *done = NULL;
+
while (next) {
struct variable *v = next;
struct type *t = v->type;
continue;
if (!t)
continue;
+ if (v->frame_pos >= 0)
+ continue;
while (done && done->scope_end < v->scope_start)
done = done->in_scope;
if (done)
pos = done->frame_pos + done->type->size;
else
- pos = 0;
+ pos = ft->function.local_size;
if (pos & (t->align - 1))
pos = (pos + t->align) & ~(t->align-1);
v->frame_pos = pos;
{
struct lrval ret = _interp_exec(c, e, dest, dtype);
if (!ret.type)
- return; // NOTEST
+ return;
if (need_free)
free_value(dtype, dest);
if (ret.lval)
fprintf(f, " = ");
if (fl->type == Tstr)
fprintf(f, "\""); // UNTESTED
- print_value(fl->type, fl->init);
+ print_value(fl->type, fl->init, f);
if (fl->type == Tstr)
fprintf(f, "\""); // UNTESTED
}
- printf("\n");
+ fprintf(f, "\n");
}
}
while (target != 0) {
int i = 0;
for (t = context.typelist; t ; t=t->next)
- if (t->print_type_decl && !t->check_args) {
+ if (t->print_type_decl && !t->check_args && t->name.txt[0] != ' ') {
i += 1;
if (i == target)
break;
do
code block
-In the first case a return type can follow the paentheses after a colon,
+In the first case a return type can follow the parentheses after a colon,
in the second it is given on a line starting with the word `return`.
##### Example: functions that return
do
code block
+Rather than returning a type, the function can specify a set of local
+variables to return as a struct. The values of these variables when the
+function exits will be provided to the caller. For this the return type
+is replaced with a block of result declarations, either in parentheses
+or bracketed by `return` and `do`.
+
+##### Example: functions returning multiple variables
+
+ func to_cartesian(rho:number; theta:number):(x:number; y:number)
+ x = .....
+ y = .....
+
+ func to_polar
+ x:number; y:number
+ return
+ rho:number
+ theta:number
+ do
+ rho = ....
+ theta = ....
-For constructing these lists we use a `List` binode, which will be
+For constructing the lists we use a `List` binode, which will be
further detailed when Expression Lists are introduced.
###### type union fields
struct binode *params;
struct type *return_type;
struct variable *scope;
+ int inline_result; // return value is at start of 'local'
int local_size;
} function;
args, NULL, 0, NULL);
}
- static void function_print(struct type *type, struct value *val)
+ static void function_print(struct type *type, struct value *val, FILE *f)
{
print_exec(val->function, 1, 0);
}
fprintf(f, ")");
if (type->function.return_type != Tnone) {
fprintf(f, ":");
- type_print(type->function.return_type, f);
+ if (type->function.inline_result) {
+ int i;
+ struct type *t = type->function.return_type;
+ fprintf(f, " (");
+ for (i = 0; i < t->structure.nfields; i++) {
+ struct field *fl = t->structure.fields + i;
+ if (i)
+ fprintf(f, "; ");
+ fprintf(f, "%.*s:", fl->name.len, fl->name.txt);
+ type_print(fl->type, f);
+ }
+ fprintf(f, ")");
+ } else
+ type_print(type->function.return_type, f);
}
fprintf(f, "\n");
}
struct val *v = cast(val, e);
if (v->vtype == Tstr)
printf("\"");
- print_value(v->vtype, &v->val);
+ print_value(v->vtype, &v->val, stdout);
if (v->vtype == Tstr)
printf("\"");
break;
When a variable is used, we need to remember to follow the `->merged`
link to find the primary instance.
+When a variable is declared, it may or may not be given an explicit
+type. We need to record which so that we can report the parsed code
+correctly.
+
###### exec type
Xvar,
struct variable *var;
};
+###### variable fields
+ int explicit_type;
+
###### Grammar
$TERM : ::
v->where_decl = $0;
v->where_set = $0;
v->type = $<Type;
+ v->explicit_type = 1;
} else {
v = var_ref(c, $1.txt);
$0->var = v;
v->where_set = $0;
v->type = $<Type;
v->constant = 1;
+ v->explicit_type = 1;
} else {
v = var_ref(c, $1.txt);
$0->var = v;
###### Binode types
CondExpr,
-###### Grammar
+###### declare terminals
$LEFT if $$ifelse
- ## expr precedence
+
+###### Grammar
$*exec
Expression -> Expression if Expression else Expression $$ifelse ${ {
OrElse,
Not,
-###### expr precedence
+###### declare terminals
$LEFT or
$LEFT and
$LEFT not
Eql,
NEql,
-###### expr precedence
+###### declare terminals
$LEFT < > <= >= == != CMPop
###### expression grammar
StringConv,
Bracket,
-###### expr precedence
+###### declare terminals
$LEFT + - Eop
$LEFT * / % ++ Top
$LEFT Uop $
arg = cast(binode, arg->right);
}
c->local = local; c->local_size = t->function.local_size;
- rv = interp_exec(c, fbody->function, &rvtype);
+ if (t->function.inline_result && dtype) {
+ _interp_exec(c, fbody->function, NULL, NULL);
+ memcpy(dest, local, dtype->size);
+ rvtype = ret.type = NULL;
+ } else
+ rv = interp_exec(c, fbody->function, &rvtype);
c->local = oldlocal; c->local_size = old_size;
free(local);
break;
list. Other stand-alone statements will follow once the infrastructure
is in-place.
+As many statements will use binodes, we declare a binode pointer 'b' in
+the common header for all reductions to use.
+
+###### Parser: reduce
+ struct binode *b;
+
###### Binode types
Block,
}$
$TERM pass
+ $*exec
SimpleStatement -> pass ${ $0 = NULL; }$
| ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$
## SimpleStatement Grammar
###### Binode types
Print,
-##### expr precedence
+##### declare terminals
$TERM print
###### SimpleStatement Grammar
| print ExpressionList ${
- $0 = new(binode);
- $0->op = Print;
- $0->right = NULL;
- $0->left = reorder_bilist($<EL);
+ $0 = b = new(binode);
+ b->op = Print;
+ b->right = NULL;
+ b->left = reorder_bilist($<EL);
}$
| print ExpressionList , ${ {
- $0 = new(binode);
- $0->op = Print;
- $0->right = reorder_bilist($<EL);
- $0->left = NULL;
+ $0 = b = new(binode);
+ b->op = Print;
+ b->right = reorder_bilist($<EL);
+ b->left = NULL;
} }$
| print ${
- $0 = new(binode);
- $0->op = Print;
- $0->left = NULL;
- $0->right = NULL;
+ $0 = b = new(binode);
+ b->op = Print;
+ b->left = NULL;
+ b->right = NULL;
}$
###### print binode cases
b2 = cast(binode, b->right);
for (; b2; b2 = cast(binode, b2->right)) {
left = interp_exec(c, b2->left, <ype);
- print_value(ltype, &left);
+ print_value(ltype, &left, stdout);
free_value(ltype, &left);
if (b2->right)
putchar(' ');
###### SimpleStatement Grammar
| Variable = Expression ${
- $0 = new(binode);
- $0->op = Assign;
- $0->left = $<1;
- $0->right = $<3;
+ $0 = b= new(binode);
+ b->op = Assign;
+ b->left = $<1;
+ b->right = $<3;
}$
| VariableDecl = Expression ${
- $0 = new(binode);
- $0->op = Declare;
- $0->left = $<1;
- $0->right =$<3;
+ $0 = b= new(binode);
+ b->op = Declare;
+ b->left = $<1;
+ b->right =$<3;
}$
| VariableDecl ${
$1, NULL, 0, NULL);
free_var($1);
} else {
- $0 = new(binode);
- $0->op = Declare;
- $0->left = $<1;
- $0->right = NULL;
+ $0 = b = new(binode);
+ b->op = Declare;
+ b->left = $<1;
+ b->right = NULL;
}
}$
print_exec(b->left, indent, bracket);
if (cast(var, b->left)->var->constant) {
printf("::");
- if (v->where_decl == v->where_set) {
+ if (v->explicit_type) {
type_print(v->type, stdout);
printf(" ");
}
} else {
printf(":");
- if (v->where_decl == v->where_set) {
+ if (v->explicit_type) {
type_print(v->type, stdout);
printf(" ");
}
propagate_types(b->left, c, ok, t,
(b->op == Assign ? Rnoconstant : 0));
}
- if (t && t->dup == NULL)
+ if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK
type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
return Tnone;
###### Binode types
Use,
-###### expr precedence
+###### declare terminals
$TERM use
###### SimpleStatement Grammar
| use Expression ${
- $0 = new_pos(binode, $1);
- $0->op = Use;
- $0->right = $<2;
- if ($0->right->type == Xvar) {
- struct var *v = cast(var, $0->right);
+ $0 = b = new_pos(binode, $1);
+ b->op = Use;
+ b->right = $<2;
+ if (b->right->type == Xvar) {
+ struct var *v = cast(var, b->right);
if (v->var->type == Tnone) {
/* Convert this to a label */
struct value *val;
###### ComplexStatement Grammar
| CondStatement ${ $0 = $<1; }$
-###### expr precedence
+###### declare terminals
$TERM for then while do
$TERM else
$TERM switch case
printf(" = ");
if (v->type == Tstr)
printf("\"");
- print_value(v->type, val);
+ print_value(v->type, val, stdout);
if (v->type == Tstr)
printf("\"");
printf("\n");
###### ast functions
+ static struct type *handle_results(struct parse_context *c,
+ struct binode *results)
+ {
+ /* Create a 'struct' type from the results list, which
+ * is a list for 'struct var'
+ */
+ struct text result_type_name = { " function_result", 5 };
+ struct type *t = add_type(c, result_type_name, &structure_prototype);
+ int cnt = 0;
+ struct binode *b;
+
+ for (b = results; b; b = cast(binode, b->right))
+ cnt += 1;
+ t->structure.nfields = cnt;
+ t->structure.fields = calloc(cnt, sizeof(struct field));
+ cnt = 0;
+ for (b = results; b; b = cast(binode, b->right)) {
+ struct var *v = cast(var, b->left);
+ struct field *f = &t->structure.fields[cnt++];
+ int a = v->var->type->align;
+ f->name = v->var->name->name;
+ f->type = v->var->type;
+ f->init = NULL;
+ f->offset = t->size;
+ v->var->frame_pos = f->offset;
+ t->size += ((f->type->size - 1) | (a-1)) + 1;
+ if (a > t->align)
+ t->align = a;
+ variable_unlink_exec(v->var);
+ }
+ free_binode(results);
+ return t;
+ }
+
static struct variable *declare_function(struct parse_context *c,
struct variable *name,
struct binode *args,
struct type *ret,
+ struct binode *results,
struct exec *code)
{
struct text funcname = {" func", 5};
if (name) {
struct value fn = {.function = code};
- name->type = add_type(c, funcname, &function_prototype);
- name->type->function.params = reorder_bilist(args);
- name->type->function.return_type = ret;
- global_alloc(c, name->type, name, &fn);
+ struct type *t;
var_block_close(c, CloseFunction, code);
+ t = add_type(c, funcname, &function_prototype);
+ name->type = t;
+ t->function.params = reorder_bilist(args);
+ if (!ret) {
+ ret = handle_results(c, reorder_bilist(results));
+ t->function.inline_result = 1;
+ t->function.local_size = ret->size;
+ }
+ t->function.return_type = ret;
+ global_alloc(c, t, name, &fn);
name->type->function.scope = c->out_scope;
} else {
free_binode(args);
$*variable
DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, Tnone, NULL, $<Bl);
}$
| func FuncName IN OpenScope Args OUT OptNL do Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, Tnone, NULL, $<Bl);
}$
| func FuncName NEWLINE OpenScope OptNL do Block Newlines ${
- $0 = declare_function(c, $<FN, NULL, Tnone, $<Bl);
+ $0 = declare_function(c, $<FN, NULL, Tnone, NULL, $<Bl);
}$
| func FuncName ( OpenScope ArgsLine ) : Type Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, $<Ty, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, $<Ty, NULL, $<Bl);
+ }$
+ | func FuncName ( OpenScope ArgsLine ) : ( ArgsLine ) Block Newlines ${
+ $0 = declare_function(c, $<FN, $<AL, NULL, $<AL2, $<Bl);
}$
| func FuncName IN OpenScope Args OUT OptNL return Type Newlines do Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, $<Ty, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, $<Ty, NULL, $<Bl);
}$
| func FuncName NEWLINE OpenScope return Type Newlines do Block Newlines ${
- $0 = declare_function(c, $<FN, NULL, $<Ty, $<Bl);
+ $0 = declare_function(c, $<FN, NULL, $<Ty, NULL, $<Bl);
+ }$
+ | func FuncName IN OpenScope Args OUT OptNL return IN Args OUT OptNL do Block Newlines ${
+ $0 = declare_function(c, $<FN, $<Ar, NULL, $<Ar2, $<Bl);
+ }$
+ | func FuncName NEWLINE OpenScope return IN Args OUT OptNL do Block Newlines ${
+ $0 = declare_function(c, $<FN, NULL, NULL, $<Ar, $<Bl);
}$
###### print func decls
if (brackets)
print_exec(val->function, 0, brackets);
else
- print_value(v->type, val);
+ print_value(v->type, val, stdout);
printf("/* frame size %d */\n", v->type->function.local_size);
target -= 1;
}
int all_ok = 1;
for (v = c->in_scope; v; v = v->in_scope) {
struct value *val;
+ struct type *ret;
int ok = 1;
if (v->depth != 0 || !v->type || !v->type->check_args)
continue;
+ ret = v->type->function.inline_result ?
+ Tnone : v->type->function.return_type;
val = var_value(c, v);
do {
ok = 1;
- propagate_types(val->function, c, &ok,
- v->type->function.return_type, 0);
+ propagate_types(val->function, c, &ok, ret, 0);
} while (ok == 2);
if (ok)
/* Make sure everything is still consistent */
- propagate_types(val->function, c, &ok,
- v->type->function.return_type, 0);
+ propagate_types(val->function, c, &ok, ret, 0);
if (!ok)
all_ok = 0;
- if (!v->type->function.return_type->dup) {
+ if (!v->type->function.inline_result &&
+ !v->type->function.return_type->dup) {
type_err(c, "error: function cannot return value of type %1",
v->where_decl, v->type->function.return_type, 0, NULL);
}