+###### core functions
+ static void resolve_consts(struct parse_context *c)
+ {
+ struct binode *b;
+ c->constlist = reorder_bilist(c->constlist);
+ for (b = cast(binode, c->constlist); b;
+ b = cast(binode, b->right)) {
+ enum prop_err perr;
+ struct binode *vb = cast(binode, b->left);
+ struct var *v = cast(var, vb->left);
+ do {
+ perr = 0;
+ propagate_types(vb->right, c, &perr,
+ v->var->type, 0);
+ } while (perr & Eretry);
+ if (perr & Efail)
+ c->parse_error += 1;
+ else {
+ struct value res = interp_exec(
+ c, vb->right, &v->var->type);
+ global_alloc(c, v->var->type, v->var, &res);
+ }
+ }
+ }
+
+###### print const decls
+ {
+ struct binode *b;
+ int first = 1;
+
+ for (b = cast(binode, context.constlist); b;
+ b = cast(binode, b->right)) {
+ struct binode *vb = cast(binode, b->left);
+ struct var *vr = cast(var, vb->left);
+ struct variable *v = vr->var;
+
+ if (first)
+ printf("const\n");
+ first = 0;
+
+ printf(" %.*s :: ", v->name->name.len, v->name->name.txt);
+ type_print(v->type, stdout);
+ printf(" = ");
+ print_exec(vb->right, -1, 0);
+ printf("\n");
+ }
+ }
+
+###### free const decls
+ free_binode(context.constlist);
+
+### Function declarations
+
+The code in an Ocean program is all stored in function declarations.
+One of the functions must be named `main` and it must accept an array of
+strings as a parameter - the command line arguments.
+
+As this is the top level, several things are handled a bit differently.
+The function is not interpreted by `interp_exec` as that isn't passed
+the argument list which the program requires. Similarly type analysis
+is a bit more interesting at this level.
+
+###### 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 type *t = add_anon_type(c, &structure_prototype,
+ " function result");
+ 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)
+ {
+ if (name) {
+ struct value fn = {.function = code};
+ struct type *t;
+ var_block_close(c, CloseFunction, code);
+ t = add_anon_type(c, &function_prototype,
+ "func %.*s", name->name->name.len,
+ name->name->name.txt);
+ 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);
+ free_type(ret);
+ free_exec(code);
+ var_block_close(c, CloseFunction, NULL);
+ }
+ c->out_scope = NULL;
+ return name;
+ }
+
+###### declare terminals
+ $TERM return
+
+###### top level grammar
+
+ $*variable
+ DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${
+ $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, NULL, $<Bl);
+ }$
+ | func FuncName NEWLINE OpenScope OptNL do Block Newlines ${
+ $0 = declare_function(c, $<FN, NULL, Tnone, NULL, $<Bl);
+ }$
+ | func FuncName ( OpenScope ArgsLine ) : Type Block Newlines ${
+ $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, NULL, $<Bl);
+ }$
+ | func FuncName NEWLINE OpenScope return Type Newlines do Block Newlines ${
+ $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