view src/ploki/compile.c @ 8916:0234daffd946

<oerjan> addquote <int-e> I couldn\'t help thinking that maybe if one considers the ramifications in full detail it will turn out that overthinking is often not helpful and therefore, not something to be proud of.
author HackBot
date Sun, 14 Aug 2016 02:31:47 +0000
parents ac0403686959
children
line wrap: on
line source

#include "config.h"
#include "Str.h"
#include "compile.h"
#include "expr.h"
#include "main_var.h"
#include "op.h"
#include "text.h"
#include "zz.h"

#include <assert.h>

static struct op *end_if(struct text *code, size_t *n) {
	for (; *n < code->length; ++*n) {
		struct op *const p = code->start[*n];
		switch (p->type) {
			case OP_IF:
				++*n;
				p->arh.op = code->start[*n];
				p->next = end_if(code, n);
				break;

			case OP_ELSE: {
				size_t tmp;
				tmp = ++*n;
				p->next = end_if(code, n);
				p->type = OP_NOP;
				if (tmp < code->length) {
					return code->start[tmp];
				}
				return p;
			}

			case OP_FI:
				p->type = OP_NOP;
				return p;

			default:
				break;
		}
	}

	return code->start[0];
}

static void resolve(struct expr *e) {
	if (!e) {
		return;
	}

	switch (e->type) {
		case literE:
			break;

		case varE:
			e->v.val = vr_data(Var_plain, e->v.tent);
			assert(e->v.val != NULL);
			break;

		case varhashE:
			e->v.hash = vr_data(Var_hash, e->v.tent);
			resolve(e->right);
			break;

		case symbolE:
			if (e->op == S_ARGV) {
				resolve(e->right);
			}
			break;

		case unopE:
			resolve(e->right);
			break;

		case binopE:
			resolve(e->left.expr);
			resolve(e->right);
			break;

		case listE:
			resolve(e->right);
			resolve(e->left.expr);
			break;
	}
}

static void op_resolve(struct op *o) {
	switch (o->type) {
		case OP_NOP:
		case OP_GOBACK:
		case OP_GOTO:
		case OP_HANG:
			break;

		case OP_ASSIGN:
		case OP_CALL_BACK:
		case OP_MODIFY:
		case OP_PRINT:
		case OP_PUTC:
		case OP_TEMP:
			resolve(o->arh.expr);
			resolve(o->arg);
			break;

		case OP_CALL:
		case OP_CALL_DYN:
		case OP_CLOSE:
		case OP_EXIT:
		case OP_IF:
		case OP_RETURN:
		case OP_SYSTEM:
		case OP_THROW:
			resolve(o->arg);
			break;

		default:
			NOTREACHED;
			break;
	}
}

void compile(struct text *code) {
	size_t i;

	for (i = 0; i < code->length; ++i) {
		struct op *const p = code->start[i];

		op_getop(p);

		if (!p->next && p->type != OP_EXIT && i + 1 < code->length) {
			p->next = code->start[i + 1];
		}
	}

	if (!i) {
		struct op tmp;
		op_init(&tmp);
		text_push(code, &tmp);
	}

	vr_freeze(Var_plain);
	vr_freeze(Var_hash);

	for (i = 0; i < code->length; ++i) {
		struct op *const p = code->start[i];

		switch (p->type) {
			case OP_IF:
				++i;
				p->arh.op = code->start[i];
				p->next = end_if(code, &i);
				break;

			case OP_ELSE:
				++i;
				p->next = end_if(code, &i);
				p->type = OP_NOP;
				break;

			case OP_FI:
				p->type = OP_NOP;
				break;

			default:
				break;
		}
	}

	for (i = 0; i < code->length; ++i) {
		op_resolve(code->start[i]);
	}
}