summaryrefslogtreecommitdiff
path: root/ev
blob: 4e33fb969e33a1ff8c57320166cbd3b14dffbb76 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env awk -f

# an evaluator of code

BEGIN {
	# prec array contains the precedence order of operators
	prec["="] = 1
	prec["+"] = prec["-"] = 2
	prec["*"] = prec["/"] = 3
	prec["^"] = 4
	# rigth array contains operators which are right associative
	right["="] = right["^"] = 1

	split("", code)
	split("", mem)
	printf "> "
}
{ line = $0; parse(); run(); printf "> " }

function scan() {
	sub(/^[ \t]+/, "", line)
	if (match(line, /^[0-9]([.0-9]*(e[+-]*)*[0-9])*/)) {
		tok = "d" substr(line, 1, RLENGTH)
	} else if (match(line, /^([][}{)(,+-=?:]|[*\/รท\^])/)) {
		tok = substr(line, 1, RLENGTH)
	} else if (match(line, /^[A-Za-z_][A-Za-z_0-9]*/)) {
		tok = "v" substr(line, 1, RLENGTH)
	} else if (match(line, /^"(\\.|[^\\"])*"/)) {
		tok = "s" substr(line, 2, RLENGTH-2)
	} else {
		tok = "b" substr(line, 1, 1)
	}
	line = substr(line, RLENGTH+1)
	return RLENGTH
}

# TODO: unary operators
function parse(   stack, sl, i) {
	i = length(code)
	while (scan() > 0) {
		if (tok == "(") {
			stack[++sl] = tok
		} else if (tok == ")") {
			while (sl && stack[sl] != "(") code[i++] = stack[sl--]
			sl--
		} else if (tok in prec) {
			# Test precedence against stack, or associativity if same precedence
			while (sl && (prec[tok] < prec[stack[sl]] || prec[tok] == prec[stack[sl]] && !(stack[sl] in right))) {
				code[i++] = stack[sl--]
			}
			stack[++sl] = tok
		} else code[i++] = tok
	}
	while (sl) code[i++] = stack[sl--]
	# for (j = 0; j < i; j++) printf("%s ", code[j]); print ""
}

# TODO: assign, if, while, function
function run(   c, i, l, t) {
	cl = length(code)
	ml = length(mem)
	i = 0
	while (i < cl) {
		c = code[i]
		if (c == "+") {
			mem[--ml] = mem[ml-1] + mem[ml]
		} else if (c == "-") {
			mem[--ml] = mem[ml-1] - mem[ml]
		} else if (c == "*") {
			mem[--ml] = mem[ml-1] * mem[ml]
		} else if (c == "/") {
			mem[--ml] = mem[ml-1] / mem[ml]
		} else if (c == "^") {
			mem[--ml] = mem[ml-1] ^ mem[ml]
		} else {
			mem[++ml] =  0 + substr(c, 2)
		}
		i++
	}
	print mem[ml]
	# for (i = ml; i in mem; i++) delete mem[i]
}