Merge remote-tracking branch 'upstream/master'
diff --git a/bc/include/bc/bc.h b/bc/include/bc/bc.h
index 8916729..4a2df7f 100644
--- a/bc/include/bc/bc.h
+++ b/bc/include/bc/bc.h
@@ -46,7 +46,9 @@
 	BC_STATUS_VM_FILE_NOT_EXECUTABLE,
 	BC_STATUS_VM_SIGACTION_FAIL,
 	BC_STATUS_VM_INVALID_STMT,
+	BC_STATUS_VM_INVALID_EXPR,
 	BC_STATUS_VM_INVALID_STRING,
+	BC_STATUS_VM_INVALID_NAME,
 	BC_STATUS_VM_PRINT_ERR,
 	BC_STATUS_VM_BREAK,
 	BC_STATUS_VM_CONTINUE,
diff --git a/bc/include/bc/data.h b/bc/include/bc/data.h
index f9ac7fe..2e4465f 100644
--- a/bc/include/bc/data.h
+++ b/bc/include/bc/data.h
@@ -31,13 +31,13 @@
 	BC_EXPR_PLUS,
 	BC_EXPR_MINUS,
 
-	BC_EXPR_ASSIGN,
-	BC_EXPR_ASSIGN_PLUS,
-	BC_EXPR_ASSIGN_MINUS,
+	BC_EXPR_ASSIGN_POWER,
 	BC_EXPR_ASSIGN_MULTIPLY,
 	BC_EXPR_ASSIGN_DIVIDE,
 	BC_EXPR_ASSIGN_MODULUS,
-	BC_EXPR_ASSIGN_POWER,
+	BC_EXPR_ASSIGN_PLUS,
+	BC_EXPR_ASSIGN_MINUS,
+	BC_EXPR_ASSIGN,
 
 	BC_EXPR_REL_EQUAL,
 	BC_EXPR_REL_LESS_EQ,
@@ -111,7 +111,7 @@
 	BcExprType type;
 	union {
 		char* string;
-		BcStack* expr_stack;
+		BcStack* exprs;
 		BcCall* call;
 		BcArrayElem* elem;
 	};
@@ -146,7 +146,7 @@
 
 	char* string;
 	struct BcStmtList* list;
-	BcStack* expr_stack;
+	BcStack* exprs;
 	BcIf* if_stmt;
 	BcWhile* while_stmt;
 	BcFor* for_stmt;
@@ -193,6 +193,19 @@
 
 } BcLocal;
 
+typedef struct BcTemp {
+
+	bool is_num;
+
+	union {
+
+		fxdpnt* num;
+		const char* name;
+
+	};
+
+} BcTemp;
+
 typedef struct BcFunc {
 
 	char* name;
@@ -263,4 +276,8 @@
 BcStatus bc_local_initArray(BcLocal* local, const char* name, uint32_t nelems);
 void bc_local_free(void* local);
 
+BcStatus bc_temp_initNum(BcTemp* temp, const char* val);
+BcStatus bc_temp_initName(BcTemp* temp, const char* name);
+void bc_temp_free(void* temp);
+
 #endif // BC_DATA_H
diff --git a/bc/include/bc/lex.h b/bc/include/bc/lex.h
index b612a80..6b37ee7 100644
--- a/bc/include/bc/lex.h
+++ b/bc/include/bc/lex.h
@@ -24,13 +24,13 @@
 	TOKEN(BC_LEX_OP_PLUS)   \
 	TOKEN(BC_LEX_OP_MINUS)  \
 	                        \
-	TOKEN(BC_LEX_OP_ASSIGN)           \
-	TOKEN(BC_LEX_OP_ASSIGN_PLUS)      \
-	TOKEN(BC_LEX_OP_ASSIGN_MINUS)     \
+	TOKEN(BC_LEX_OP_ASSIGN_POWER)     \
 	TOKEN(BC_LEX_OP_ASSIGN_MULTIPLY)  \
 	TOKEN(BC_LEX_OP_ASSIGN_DIVIDE)    \
 	TOKEN(BC_LEX_OP_ASSIGN_MODULUS)   \
-	TOKEN(BC_LEX_OP_ASSIGN_POWER)     \
+	TOKEN(BC_LEX_OP_ASSIGN_PLUS)      \
+	TOKEN(BC_LEX_OP_ASSIGN_MINUS)     \
+	TOKEN(BC_LEX_OP_ASSIGN)           \
 	                                  \
 	TOKEN(BC_LEX_OP_REL_EQUAL)       \
 	TOKEN(BC_LEX_OP_REL_LESS_EQ)     \
diff --git a/bc/include/bc/program.h b/bc/include/bc/program.h
index 2c0c3db..a495c3b 100644
--- a/bc/include/bc/program.h
+++ b/bc/include/bc/program.h
@@ -13,6 +13,10 @@
 
 	uint32_t stmt_idx;
 
+	uint32_t scale;
+	uint32_t ibase;
+	uint32_t obase;
+
 	BcStack ctx_stack;
 
 	BcStack locals;
diff --git a/bc/main.c b/bc/main.c
index becb133..1f16945 100644
--- a/bc/main.c
+++ b/bc/main.c
@@ -1,5 +1,8 @@
+#include <locale.h>
+
 #include <bc/bc.h>
 
 int main(int argc, char* argv[]) {
+	setlocale(LC_ALL, "");
 	return bc_main(argc, argv);
 }
diff --git a/bc/src/bc.c b/bc/src/bc.c
index e70ccfe..6fdade5 100644
--- a/bc/src/bc.c
+++ b/bc/src/bc.c
@@ -51,6 +51,8 @@
     "runtime",
     "runtime",
     "runtime",
+    "runtime",
+    "runtime",
 
 };
 
@@ -90,7 +92,9 @@
     "file is not executable",
     "could not install signal handler",
     "invalid statement; this is most likely a bug in bc",
+    "invalid expression; this is most likely a bug in bc",
     "invalid string",
+    "invalid name/identifier",
     "print error",
     "break statement outside loop; "
         "this is a bug in bc (parser should have caught it)",
diff --git a/bc/src/data.c b/bc/src/data.c
index c3bfa98..0a326b0 100644
--- a/bc/src/data.c
+++ b/bc/src/data.c
@@ -440,9 +440,9 @@
 
 	if (bc_stmt_sizes[type]) {
 
-		stmt->data.expr_stack = malloc(bc_stmt_sizes[type]);
+		stmt->data.exprs = malloc(bc_stmt_sizes[type]);
 
-		if (!stmt->data.expr_stack) {
+		if (!stmt->data.exprs) {
 			return BC_STATUS_MALLOC_FAIL;
 		}
 	}
@@ -465,8 +465,8 @@
 		case BC_STMT_EXPR:
 		case BC_STMT_RETURN:
 		{
-			bc_stack_free(stmt->data.expr_stack);
-			free(stmt->data.expr_stack);
+			bc_stack_free(stmt->data.exprs);
+			free(stmt->data.exprs);
 			break;
 		}
 
@@ -527,7 +527,7 @@
 		}
 	}
 
-	stmt->data.expr_stack = NULL;
+	stmt->data.exprs = NULL;
 }
 
 BcIf* bc_if_create() {
@@ -615,8 +615,8 @@
 		case BC_EXPR_LENGTH:
 		case BC_EXPR_SQRT:
 		{
-			bc_stack_free(e->expr_stack);
-			free(e->expr_stack);
+			bc_stack_free(e->exprs);
+			free(e->exprs);
 			break;
 		}
 
@@ -706,3 +706,41 @@
 		l->num_elems = 0;
 	}
 }
+
+BcStatus bc_temp_initNum(BcTemp* temp, const char* val) {
+
+	temp->is_num = true;
+
+	if (val) {
+		temp->num = arb_str2fxdpnt(val);
+	}
+	else {
+		temp->num = arb_alloc(BC_PROGRAM_DEF_SIZE);
+	}
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_temp_initName(BcTemp* temp, const char* name) {
+
+	temp->is_num = false;
+
+	if (!name) {
+		return BC_STATUS_VM_INVALID_NAME;
+	}
+
+	temp->name = name;
+
+	return BC_STATUS_SUCCESS;
+}
+
+void bc_temp_free(void* temp) {
+
+	BcTemp* t;
+
+	t = (BcTemp*) temp;
+
+	if (t->is_num) {
+		arb_free(t->num);
+	}
+}
diff --git a/bc/src/lex.c b/bc/src/lex.c
index 30b2882..b71e100 100644
--- a/bc/src/lex.c
+++ b/bc/src/lex.c
@@ -553,31 +553,16 @@
 
 	size_t len = i - lex->idx;
 
-	size_t backslashes = 0;
-	for (size_t j = lex->idx; j < i; ++j) {
-		c = lex->buffer[j];
-		backslashes += c == '\\' && lex->buffer[j + 1] == '\n' ? 1 : 0;
-	}
-
-	token->string = malloc(len - backslashes + 1);
+	token->string = malloc(len + 1);
 
 	if (token->string == NULL) {
 		return BC_STATUS_MALLOC_FAIL;
 	}
 
 	const char* start = lex->buffer + lex->idx;
-	size_t hits = 0;
 
 	for (size_t j = 0; j < len; ++j) {
-
-		char c = start[j];
-
-		if (hits < backslashes && c == '\\' && start[j + 1] == '\n') {
-			++hits;
-			continue;
-		}
-
-		token->string[j - hits] = c;
+		token->string[j] = start[j];
 	}
 
 	token->string[len] = '\0';
@@ -645,8 +630,8 @@
 	size_t i = 0;
 	char c = buffer[i];
 
-	while (c && (isdigit(c) || (c >= 'A' && c <= 'F') || (c == '.' && !point) ||
-	             (c == '\\' && buffer[i + 1] == '\n')))
+	while (c && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
+	             (c == '.' && !point) || (c == '\\' && buffer[i + 1] == '\n')))
 	{
 		if (c == '\\') {
 			++i;
@@ -715,7 +700,7 @@
 	size_t i = 0;
 	char c = buffer[i];
 
-	while (islower(c) || isdigit(c) || c == '_') {
+	while ((c >= 'a' && c<= 'z') || (c >= '0' && c <= '9') || c == '_') {
 		++i;
 		c = buffer[i];
 	}
diff --git a/bc/src/parse.c b/bc/src/parse.c
index 4472dcf..1c24293 100644
--- a/bc/src/parse.c
+++ b/bc/src/parse.c
@@ -715,7 +715,7 @@
 				break;
 			}
 
-			status = bc_parse_expr(parse, stmt.data.expr_stack);
+			status = bc_parse_expr(parse, stmt.data.exprs);
 
 			if (status) {
 				bc_stmt_free(&stmt);
@@ -999,13 +999,13 @@
 				break;
 			}
 
-			case BC_LEX_OP_ASSIGN:
-			case BC_LEX_OP_ASSIGN_PLUS:
-			case BC_LEX_OP_ASSIGN_MINUS:
+			case BC_LEX_OP_ASSIGN_POWER:
 			case BC_LEX_OP_ASSIGN_MULTIPLY:
 			case BC_LEX_OP_ASSIGN_DIVIDE:
 			case BC_LEX_OP_ASSIGN_MODULUS:
-			case BC_LEX_OP_ASSIGN_POWER:
+			case BC_LEX_OP_ASSIGN_PLUS:
+			case BC_LEX_OP_ASSIGN_MINUS:
+			case BC_LEX_OP_ASSIGN:
 			{
 				if (prev != BC_EXPR_VAR && prev != BC_EXPR_ARRAY_ELEM &&
 				    prev != BC_EXPR_SCALE && prev != BC_EXPR_IBASE &&
@@ -1215,8 +1215,8 @@
 
 	expr.type = ((BcExpr*) bc_stack_top(exprs))->type;
 
-	if (expr.type < BC_EXPR_ASSIGN ||
-	    expr.type > BC_EXPR_ASSIGN_POWER ||
+	if (expr.type < BC_EXPR_ASSIGN_POWER ||
+	    expr.type > BC_EXPR_ASSIGN ||
 	    paren_first)
 	{
 		expr.type = BC_EXPR_PRINT;
@@ -1367,7 +1367,7 @@
 	char* name;
 
 	name = parse->token.string;
-	expr.expr_stack = NULL;
+	expr.exprs = NULL;
 
 	status = bc_lex_next(&parse->lex, &parse->token);
 
@@ -1381,9 +1381,9 @@
 		*type = BC_EXPR_ARRAY_ELEM;
 		expr.string = name;
 
-		expr.expr_stack = malloc(sizeof(BcStack));
+		expr.exprs = malloc(sizeof(BcStack));
 
-		if (!expr.expr_stack) {
+		if (!expr.exprs) {
 			return BC_STATUS_MALLOC_FAIL;
 		}
 
@@ -1393,7 +1393,7 @@
 			goto name_err;
 		}
 
-		status = bc_parse_expr(parse, expr.expr_stack);
+		status = bc_parse_expr(parse, expr.exprs);
 
 		if (status) {
 			goto name_err;
@@ -1430,7 +1430,7 @@
 
 	status = bc_stack_push(exprs, &expr);
 
-	if (status && expr.expr_stack) {
+	if (status && expr.exprs) {
 		goto name_err;
 	}
 
@@ -1438,8 +1438,8 @@
 
 name_err:
 
-	free(expr.expr_stack);
-	expr.expr_stack = NULL;
+	free(expr.exprs);
+	expr.exprs = NULL;
 
 	return status;
 }
@@ -1584,13 +1584,13 @@
 		return status;
 	}
 
-	expr.expr_stack = malloc(sizeof(BcStack));
+	expr.exprs = malloc(sizeof(BcStack));
 
-	if (!expr.expr_stack) {
+	if (!expr.exprs) {
 		return BC_STATUS_MALLOC_FAIL;
 	}
 
-	status = bc_parse_expr(parse, expr.expr_stack);
+	status = bc_parse_expr(parse, expr.exprs);
 
 	if (status) {
 		goto init_err;
@@ -1611,7 +1611,7 @@
 
 init_err:
 
-	free(expr.expr_stack);
+	free(expr.exprs);
 
 	return status;
 }
@@ -1638,13 +1638,13 @@
 	expr.type = BC_EXPR_SCALE_FUNC;
 	*type = BC_EXPR_SCALE_FUNC;
 
-	expr.expr_stack = malloc(sizeof(BcStack));
+	expr.exprs = malloc(sizeof(BcStack));
 
-	if (!expr.expr_stack) {
+	if (!expr.exprs) {
 		return BC_STATUS_MALLOC_FAIL;
 	}
 
-	status = bc_parse_expr(parse, expr.expr_stack);
+	status = bc_parse_expr(parse, expr.exprs);
 
 	if (status) {
 		goto parse_err;
@@ -1671,7 +1671,7 @@
 
 parse_err:
 
-	free(expr.expr_stack);
+	free(expr.exprs);
 
 	return status;
 }
@@ -1813,16 +1813,16 @@
 
 	stmt.type = BC_STMT_RETURN;
 
-	stmt.data.expr_stack = malloc(sizeof(BcStack));
+	stmt.data.exprs = malloc(sizeof(BcStack));
 
-	if (!stmt.data.expr_stack) {
+	if (!stmt.data.exprs) {
 		return BC_STATUS_MALLOC_FAIL;
 	}
 
 	if (parse->token.type == BC_LEX_NEWLINE ||
 	    parse->token.type == BC_LEX_SEMICOLON)
 	{
-		status = bc_stack_init(stmt.data.expr_stack, sizeof(BcExpr), bc_expr_free);
+		status = bc_stack_init(stmt.data.exprs, sizeof(BcExpr), bc_expr_free);
 
 		if (status) {
 			goto parse_err;
@@ -1831,7 +1831,7 @@
 		expr.type = BC_EXPR_NUMBER;
 		expr.string = NULL;
 
-		status = bc_stack_push(stmt.data.expr_stack, &expr);
+		status = bc_stack_push(stmt.data.exprs, &expr);
 
 		if (status) {
 			goto push_err;
@@ -1839,7 +1839,7 @@
 	}
 	else {
 
-		status = bc_parse_expr(parse, stmt.data.expr_stack);
+		status = bc_parse_expr(parse, stmt.data.exprs);
 
 		if (status) {
 			goto parse_err;
@@ -1856,11 +1856,11 @@
 
 push_err:
 
-	bc_stack_free(stmt.data.expr_stack);
+	bc_stack_free(stmt.data.exprs);
 
 parse_err:
 
-	free(stmt.data.expr_stack);
+	free(stmt.data.exprs);
 
 	return status;
 }
@@ -1913,14 +1913,14 @@
 				return status;
 			}
 
-			status = bc_parse_expr(parse, stmt.data.expr_stack);
+			status = bc_parse_expr(parse, stmt.data.exprs);
 
 			if (status) {
 				goto expr_err;
 			}
 
 			expr.type = BC_EXPR_PRINT;
-			status = bc_stack_push(stmt.data.expr_stack, &expr);
+			status = bc_stack_push(stmt.data.exprs, &expr);
 
 			if (status) {
 				goto parse_err;
@@ -1961,11 +1961,11 @@
 
 parse_err:
 
-	bc_stack_free(stmt.data.expr_stack);
+	bc_stack_free(stmt.data.exprs);
 
 expr_err:
 
-	free(stmt.data.expr_stack);
+	free(stmt.data.exprs);
 
 	return status;
 }
diff --git a/bc/src/program.c b/bc/src/program.c
index 2cb20ad..c56e8f1 100644
--- a/bc/src/program.c
+++ b/bc/src/program.c
@@ -9,7 +9,7 @@
 
 static BcStatus bc_program_execList(BcProgram* p, BcStmtList* list);
 static BcStatus bc_program_printString(const char* str);
-static BcStatus bc_program_execExpr(BcProgram* p, BcStmt* stmt,
+static BcStatus bc_program_execExpr(BcProgram* p, BcStack* exprs,
                                     fxdpnt* num, bool print);
 
 BcStatus bc_program_init(BcProgram* p, const char* file) {
@@ -59,7 +59,7 @@
 		goto local_err;
 	}
 
-	st = bc_stack_init(&p->temps, sizeof(fxdpnt), (BcFreeFunc) arb_free);
+	st = bc_stack_init(&p->temps, sizeof(BcTemp), bc_temp_free);
 
 	if (st) {
 		goto temps_err;
@@ -123,7 +123,38 @@
 }
 
 BcStatus bc_program_exec(BcProgram* p) {
-	return bc_program_execList(p, p->list);
+
+	BcStmtList* list;
+	BcStatus status;
+
+	status = bc_program_execList(p, p->list);
+
+	if (status) {
+		return status;
+	}
+
+	while (p->list->idx >= BC_PROGRAM_MAX_STMTS) {
+
+		if (p->list->next) {
+
+			list = p->list;
+			p->list = list->next;
+
+			bc_list_destruct(list);
+		}
+		else {
+
+			bc_list_destruct(p->list);
+
+			p->list = bc_list_create();
+
+			if (!p->list) {
+				return BC_STATUS_MALLOC_FAIL;
+			}
+		}
+	}
+
+	return BC_STATUS_SUCCESS;
 }
 
 void bc_program_free(BcProgram* p) {
@@ -174,7 +205,7 @@
 
 				case BC_STMT_EXPR:
 				{
-					status = bc_program_execExpr(p, stmt, &result, true);
+					status = bc_program_execExpr(p, stmt->data.exprs, &result, true);
 
 					if (status) {
 						break;
@@ -355,8 +386,231 @@
 	return BC_STATUS_SUCCESS;
 }
 
-static BcStatus bc_program_execExpr(BcProgram* p, BcStmt* stmt,
+static BcStatus bc_program_execExpr(BcProgram* p, BcStack* exprs,
                                     fxdpnt* num, bool print)
 {
+	BcStatus status;
+	uint32_t idx;
+	BcExpr* expr;
+	BcTemp temp;
+	uint32_t temp_len;
+	fxdpnt temp_num;
 
+	status = BC_STATUS_SUCCESS;
+
+	temp_len = p->temps.len;
+
+	idx = exprs->len - 1;
+
+	while (idx < exprs->len) {
+
+		expr = bc_stack_item(exprs, idx);
+
+		if (!expr) {
+			return BC_STATUS_VM_INVALID_EXPR;
+		}
+
+		switch (expr->type) {
+
+			case BC_EXPR_INC_PRE:
+			case BC_EXPR_DEC_PRE:
+			{
+				break;
+			}
+
+			case BC_EXPR_INC_POST:
+			case BC_EXPR_DEC_POST:
+			{
+				break;
+			}
+
+			case BC_EXPR_NEGATE:
+			{
+				break;
+			}
+
+			case BC_EXPR_POWER:
+			{
+				break;
+			}
+
+			case BC_EXPR_MULTIPLY:
+			{
+				break;
+			}
+
+			case BC_EXPR_DIVIDE:
+			{
+				break;
+			}
+
+			case BC_EXPR_MODULUS:
+			{
+				break;
+			}
+
+			case BC_EXPR_PLUS:
+			{
+				break;
+			}
+
+			case BC_EXPR_MINUS:
+			{
+				break;
+			}
+
+			case BC_EXPR_ASSIGN_POWER:
+			case BC_EXPR_ASSIGN_MULTIPLY:
+			case BC_EXPR_ASSIGN_DIVIDE:
+			case BC_EXPR_ASSIGN_MODULUS:
+			case BC_EXPR_ASSIGN_PLUS:
+			case BC_EXPR_ASSIGN_MINUS:
+			{
+				// Fallthrough.
+			}
+			case BC_EXPR_ASSIGN:
+			{
+				break;
+			}
+
+			case BC_EXPR_REL_EQUAL:
+			case BC_EXPR_REL_LESS_EQ:
+			case BC_EXPR_REL_GREATER_EQ:
+			case BC_EXPR_REL_NOT_EQ:
+			case BC_EXPR_REL_LESS:
+			case BC_EXPR_REL_GREATER:
+			{
+				break;
+			}
+
+			case BC_EXPR_BOOL_NOT:
+			{
+				break;
+			}
+
+			case BC_EXPR_BOOL_OR:
+			{
+				break;
+			}
+
+			case BC_EXPR_BOOL_AND:
+			{
+				break;
+			}
+
+			case BC_EXPR_NUMBER:
+			{
+				status = bc_temp_initNum(&temp, expr->string);
+
+				if (status) {
+					break;
+				}
+
+				status = bc_stack_push(&p->temps, &temp);
+
+				break;
+			}
+
+			case BC_EXPR_VAR:
+			{
+				break;
+			}
+
+			case BC_EXPR_ARRAY_ELEM:
+			{
+				break;
+			}
+
+			case BC_EXPR_FUNC_CALL:
+			{
+				break;
+			}
+
+			case BC_EXPR_SCALE:
+			{
+				break;
+			}
+
+			case BC_EXPR_SCALE_FUNC:
+			{
+				break;
+			}
+
+			case BC_EXPR_IBASE:
+			{
+				break;
+			}
+
+			case BC_EXPR_OBASE:
+			{
+				break;
+			}
+
+			case BC_EXPR_LAST:
+			{
+				break;
+			}
+
+			case BC_EXPR_LENGTH:
+			{
+				break;
+			}
+
+			case BC_EXPR_READ:
+			{
+				break;
+			}
+
+			case BC_EXPR_SQRT:
+			{
+				status = bc_program_execExpr(p, expr->exprs, &temp_num, false);
+
+				if (status) {
+					break;
+				}
+
+				if (temp_num.sign != '-') {
+
+					status = bc_temp_initNum(&temp, NULL);
+
+					if (status) {
+						break;
+					}
+
+					arb_newton_sqrt(&temp_num, temp.num, 10, p->scale);
+				}
+				else {
+					status = BC_STATUS_VM_NEG_SQRT;
+				}
+
+				break;
+			}
+
+			case BC_EXPR_PRINT:
+			{
+				// TODO: Store to last and print.
+				if (!print) {
+					break;
+				}
+
+				break;
+			}
+
+			default:
+			{
+				status = BC_STATUS_VM_INVALID_EXPR;
+				break;
+			}
+		}
+	}
+
+	if (status) {
+		return status;
+	}
+
+	if (p->temps.len != temp_len) {
+		return BC_STATUS_VM_INVALID_EXPR;
+	}
+
+	return status;
 }