1781 lines
44 KiB
C
1781 lines
44 KiB
C
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
|
|
#include <gmp.h>
|
|
|
|
#include <readline/readline.h>
|
|
#include <readline/history.h>
|
|
|
|
#include "avl.h"
|
|
|
|
#define TODO assert(!"TODO");
|
|
|
|
#define argv0 program_invocation_name
|
|
|
|
#ifdef ZDEBUG
|
|
#define zprintf(fmt, ...) \
|
|
printf(fmt, ## __VA_ARGS__);
|
|
#else
|
|
#define zprintf(...);
|
|
#endif
|
|
|
|
const char* command = NULL;
|
|
|
|
static void parse_args(int argc, char* const* argv)
|
|
{
|
|
for (int opt; (opt = getopt(argc, argv, "c:")) != -1; ) switch (opt)
|
|
{
|
|
case 'c':
|
|
command = optarg;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
printf("Unknown option '%c'!" "\n", opt);
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct string
|
|
{
|
|
char* data;
|
|
unsigned refcount;
|
|
};
|
|
|
|
struct string* new_string(const char* data_ro)
|
|
{
|
|
struct string* this = malloc(sizeof(*this));
|
|
|
|
this->data = strdup(data_ro);
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct string* new_string_from_fmt(const char* fmt, ...)
|
|
{
|
|
struct string* this = malloc(sizeof(*this));
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
int x = vasprintf(&this->data, fmt, ap);
|
|
|
|
if (x < 0)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
this->refcount = 1;
|
|
|
|
va_end(ap);
|
|
|
|
return this;
|
|
}
|
|
|
|
struct string* inc_string(struct string* this)
|
|
{
|
|
if (this)
|
|
this->refcount++;
|
|
|
|
return this;
|
|
}
|
|
|
|
void free_string(struct string* this)
|
|
{
|
|
if (this && !--this->refcount)
|
|
{
|
|
free(this->data);
|
|
free(this);
|
|
}
|
|
}
|
|
|
|
struct value;
|
|
|
|
struct value* inc_value(struct value* this);
|
|
|
|
void free_value(struct value* this);
|
|
|
|
struct expression
|
|
{
|
|
enum expression_kind {
|
|
ek_syntax_error,
|
|
|
|
// primary:
|
|
ek_literal,
|
|
ek_variable,
|
|
|
|
// arithmetic operators:
|
|
ek_positive,
|
|
ek_negative,
|
|
ek_add,
|
|
ek_subtract,
|
|
ek_multiply,
|
|
ek_divide,
|
|
|
|
// comparision operators:
|
|
ek_greater_than,
|
|
ek_less_than,
|
|
ek_greater_than_equal_to,
|
|
ek_less_than_equal_to,
|
|
|
|
// equality operators:
|
|
ek_equal_to,
|
|
ek_not_equal_to,
|
|
|
|
// logical operators:
|
|
ek_logical_not,
|
|
ek_logical_and,
|
|
ek_logical_or,
|
|
|
|
ek_ternary,
|
|
|
|
ek_assign,
|
|
|
|
ek_comma,
|
|
} kind;
|
|
|
|
struct string* string;
|
|
|
|
struct expression* center;
|
|
struct expression* left;
|
|
struct expression* right;
|
|
|
|
struct value* value;
|
|
|
|
unsigned refcount;
|
|
};
|
|
|
|
struct expression* inc_expression(struct expression* this);
|
|
|
|
struct expression* new_syntax_error_expression(
|
|
struct string* error_message,
|
|
struct expression* subexpression)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_syntax_error;
|
|
this->string = inc_string(error_message);
|
|
this->center = inc_expression(subexpression);
|
|
this->left = this->right = NULL;
|
|
this->value = NULL;
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* new_literal_expression(
|
|
struct value* value)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_literal;
|
|
this->string = NULL;;
|
|
this->center = NULL;
|
|
this->left = this->right = NULL;
|
|
this->value = inc_value(value);
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* new_variable_expression(
|
|
struct string* variable)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_variable;
|
|
this->string = inc_string(variable);
|
|
this->center = NULL;
|
|
this->left = this->right = NULL;
|
|
this->value = NULL;
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* new_logical_not_expression(
|
|
struct expression* sub)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_logical_not;
|
|
this->string = NULL;
|
|
this->center = inc_expression(sub);
|
|
this->left = NULL;
|
|
this->right = NULL;
|
|
this->value = NULL;
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* new_positive_expression(
|
|
struct expression* sub)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_positive;
|
|
this->string = NULL;
|
|
this->center = inc_expression(sub);
|
|
this->left = NULL;
|
|
this->right = NULL;
|
|
this->value = NULL;
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* new_negative_expression(
|
|
struct expression* sub)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_negative;
|
|
this->string = NULL;
|
|
this->center = inc_expression(sub);
|
|
this->left = NULL;
|
|
this->right = NULL;
|
|
this->value = NULL;
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* new_binary_expression(
|
|
enum expression_kind kind,
|
|
struct expression* left,
|
|
struct expression* right)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = kind;
|
|
this->string = NULL;
|
|
this->center = NULL;
|
|
this->left = inc_expression(left);
|
|
this->right = inc_expression(right);
|
|
this->value = NULL;
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct expression* inc_expression(struct expression* this)
|
|
{
|
|
if (this)
|
|
this->refcount++;
|
|
|
|
return this;
|
|
}
|
|
|
|
void free_expression(struct expression* this)
|
|
{
|
|
if (this && !--this->refcount)
|
|
{
|
|
free_string(this->string);
|
|
|
|
free_expression(this->center);
|
|
free_expression(this->left);
|
|
free_expression(this->right);
|
|
|
|
free_value(this->value);
|
|
|
|
free(this);
|
|
}
|
|
}
|
|
|
|
struct value
|
|
{
|
|
mpq_t mpq;
|
|
unsigned refcount;
|
|
};
|
|
|
|
struct value* new_value_from_int(int x)
|
|
{
|
|
struct value* this = malloc(sizeof(*this));
|
|
|
|
mpq_init(this->mpq);
|
|
|
|
mpq_set_si(this->mpq, x, 1);
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct value* new_value(mpq_t mpq)
|
|
{
|
|
struct value* this = malloc(sizeof(*this));
|
|
|
|
mpq_init(this->mpq);
|
|
|
|
mpq_set(this->mpq, mpq);
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct value* inc_value(struct value* this)
|
|
{
|
|
if (this)
|
|
this->refcount++;
|
|
|
|
return this;
|
|
}
|
|
|
|
void free_value(struct value* this)
|
|
{
|
|
if (this && !--this->refcount)
|
|
{
|
|
mpq_clear(this->mpq);
|
|
|
|
free(this);
|
|
}
|
|
}
|
|
|
|
struct value* scan(const char* text)
|
|
{
|
|
const char* moving = text;
|
|
|
|
mpq_t base; mpq_init(base);
|
|
mpq_t tmp; mpq_init(tmp);
|
|
mpq_t value; mpq_init(value);
|
|
|
|
mpq_set_si(value, 0, 1);
|
|
mpq_set_si(base, 10, 1);
|
|
|
|
while ('0' <= *moving && *moving <= '9')
|
|
{
|
|
mpq_set_si(tmp, *moving++ - '0', 1);
|
|
|
|
mpq_mul(value, value, base);
|
|
mpq_add(value, value, tmp);
|
|
}
|
|
|
|
if (*moving == '.')
|
|
{
|
|
mpq_t factor; mpq_init(factor);
|
|
|
|
moving++;
|
|
|
|
mpq_set_si(factor, 1, 10);
|
|
|
|
while ('0' <= *moving && *moving <= '9')
|
|
{
|
|
mpq_set_si(tmp, *moving++ - '0', 1);
|
|
|
|
mpq_mul(tmp, factor, tmp);
|
|
|
|
mpq_add(value, value, tmp);
|
|
|
|
mpq_div(factor, factor, base);
|
|
}
|
|
|
|
mpq_clear(factor);
|
|
}
|
|
|
|
assert(!*moving);
|
|
|
|
struct value* retval = new_value(value);
|
|
|
|
mpq_clear(base);
|
|
mpq_clear(tmp);
|
|
mpq_clear(value);
|
|
|
|
return retval;
|
|
}
|
|
|
|
struct scope
|
|
{
|
|
avl_tree_t* tree;
|
|
};
|
|
|
|
struct variable
|
|
{
|
|
struct string* name;
|
|
struct value* value;
|
|
};
|
|
|
|
struct variable* new_variable(struct string* name)
|
|
{
|
|
struct variable* this = malloc(sizeof(*this));
|
|
|
|
this->name = inc_string(name);
|
|
this->value = NULL;
|
|
|
|
return this;
|
|
}
|
|
|
|
int compare_variable(const void* a, const void* b)
|
|
{
|
|
const struct variable* A = a, *B = b;
|
|
|
|
return strcmp(A->name->data, B->name->data);
|
|
}
|
|
|
|
void free_variable(void* ptr)
|
|
{
|
|
struct variable* this = ptr;
|
|
|
|
free_string(this->name);
|
|
|
|
free_value(this->value);
|
|
|
|
free(this);
|
|
}
|
|
|
|
struct scope* new_scope(void)
|
|
{
|
|
struct scope* this = malloc(sizeof(*this));
|
|
|
|
this->tree = avl_alloc_tree(compare_variable, free_variable);
|
|
|
|
return this;
|
|
}
|
|
|
|
struct value** scope_lookup(
|
|
struct scope* this,
|
|
struct string* name)
|
|
{
|
|
struct avl_node_t* node = avl_search(this->tree, &name);
|
|
|
|
if (!node)
|
|
{
|
|
struct variable* var = new_variable(name);
|
|
|
|
node = avl_insert(this->tree, var);
|
|
}
|
|
|
|
return &((struct variable*) node->item)->value;
|
|
}
|
|
|
|
void free_scope(struct scope* this)
|
|
{
|
|
avl_free_tree(this->tree);
|
|
|
|
free(this);
|
|
}
|
|
|
|
struct expression* parse(const char* text)
|
|
{
|
|
enum {
|
|
tk_uninitialized,
|
|
|
|
// primary:
|
|
tk_identifier,
|
|
tk_literal,
|
|
|
|
// brakets:
|
|
tk_oparen,
|
|
tk_cparen,
|
|
|
|
// arithmetic operators:
|
|
tk_plus,
|
|
tk_minus,
|
|
tk_asterisk,
|
|
tk_slash,
|
|
|
|
// comparision operators:
|
|
tk_less_than,
|
|
tk_less_than_eq,
|
|
|
|
tk_greater_than,
|
|
tk_greater_than_eq,
|
|
|
|
tk_emarkequals,
|
|
tk_equalsequals,
|
|
|
|
// logical operators:
|
|
tk_vbarvbar,
|
|
tk_ampersandampersand,
|
|
|
|
// misc:
|
|
tk_emark,
|
|
tk_qmark,
|
|
tk_colon,
|
|
tk_equals,
|
|
tk_comma,
|
|
|
|
tk_EOF,
|
|
|
|
number_of_tokens,
|
|
} tokenkind = tk_uninitialized;
|
|
|
|
static const char* const tokennames[number_of_tokens] = {
|
|
[tk_EOF] = "EOF",
|
|
|
|
[tk_identifier] = "identifier",
|
|
[tk_literal] = "literal",
|
|
[tk_oparen] = "(",
|
|
[tk_cparen] = ")",
|
|
[tk_plus] = "+",
|
|
[tk_minus] = "-",
|
|
[tk_asterisk] = "*",
|
|
[tk_slash] = "/",
|
|
[tk_less_than] = "<",
|
|
[tk_less_than_eq] = "<=",
|
|
[tk_greater_than] = ">",
|
|
[tk_greater_than_eq] = ">=",
|
|
[tk_emarkequals] = "!=",
|
|
[tk_equalsequals] = "==",
|
|
[tk_vbarvbar] = "||",
|
|
[tk_ampersandampersand] = "&&",
|
|
[tk_emark] = "!",
|
|
[tk_qmark] = "?",
|
|
[tk_colon] = ":",
|
|
[tk_equals] = "=",
|
|
[tk_comma] = ",",
|
|
};
|
|
|
|
struct {
|
|
char* data;
|
|
size_t n, cap;
|
|
} buffer = {};
|
|
|
|
void append(char c)
|
|
{
|
|
if (buffer.n == buffer.cap)
|
|
{
|
|
buffer.cap = buffer.cap << 1 ?: 1;
|
|
buffer.data = realloc(buffer.data, sizeof(*buffer.data) * buffer.cap);
|
|
}
|
|
|
|
buffer.data[buffer.n++] = c;
|
|
}
|
|
|
|
const char* moving = text;
|
|
|
|
void next_token(void)
|
|
{
|
|
while (*moving && *moving == ' ')
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case 0:
|
|
tokenkind = tk_EOF;
|
|
break;
|
|
|
|
case '0' ... '9':
|
|
{
|
|
buffer.n = 0;
|
|
|
|
while (false
|
|
|| *moving == '_'
|
|
|| *moving == '.'
|
|
|| ('0' <= *moving && *moving <= '9'))
|
|
{
|
|
append(*moving++);
|
|
}
|
|
|
|
append(0);
|
|
|
|
tokenkind = tk_literal;
|
|
break;
|
|
}
|
|
|
|
case '_':
|
|
case 'a' ... 'z':
|
|
case 'A' ... 'Z':
|
|
{
|
|
buffer.n = 0;
|
|
|
|
while (false
|
|
|| *moving == '_'
|
|
|| ('a' <= *moving && *moving <= 'z')
|
|
|| ('A' <= *moving && *moving <= 'Z'))
|
|
{
|
|
append(*moving++);
|
|
}
|
|
|
|
append(0);
|
|
|
|
tokenkind = tk_identifier;
|
|
break;
|
|
}
|
|
|
|
case '+': tokenkind = tk_plus, moving++; break;
|
|
case '-': tokenkind = tk_minus, moving++; break;
|
|
case '*': tokenkind = tk_asterisk, moving++; break;
|
|
case '/': tokenkind = tk_slash, moving++; break;
|
|
|
|
case '(': tokenkind = tk_oparen, moving++; break;
|
|
case ')': tokenkind = tk_cparen, moving++; break;
|
|
|
|
case '?': tokenkind = tk_qmark, moving++; break;
|
|
case ':': tokenkind = tk_colon, moving++; break;
|
|
|
|
case ',': tokenkind = tk_comma, moving++; break;
|
|
|
|
case '|':
|
|
{
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case '|':
|
|
tokenkind = tk_vbarvbar, moving++;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
TODO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '&':
|
|
{
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case '&':
|
|
tokenkind = tk_ampersandampersand, moving++;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
TODO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '!':
|
|
{
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case '=':
|
|
tokenkind = tk_emarkequals, moving++;
|
|
break;
|
|
|
|
default:
|
|
tokenkind = tk_emark;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '<':
|
|
{
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case '=':
|
|
tokenkind = tk_less_than_eq, moving++;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
tokenkind = tk_less_than;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '>':
|
|
{
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case '=':
|
|
tokenkind = tk_greater_than_eq, moving++;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
tokenkind = tk_greater_than;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '=':
|
|
{
|
|
moving++;
|
|
|
|
switch (*moving)
|
|
{
|
|
case '=':
|
|
tokenkind = tk_equalsequals, moving++;
|
|
break;
|
|
|
|
default:
|
|
tokenkind = tk_equals, moving++;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
assert(!"TODO");
|
|
break;
|
|
}
|
|
}
|
|
|
|
next_token();
|
|
|
|
struct expression* parse_root(void)
|
|
{
|
|
struct expression* parse_comma(void)
|
|
{
|
|
struct expression* parse_assign(void)
|
|
{
|
|
struct expression* parse_ternary(void)
|
|
{
|
|
struct expression* parse_logicals(void)
|
|
{
|
|
struct expression* parse_equality(void)
|
|
{
|
|
struct expression* parse_comparision(void)
|
|
{
|
|
struct expression* parse_arithmetic(void)
|
|
{
|
|
struct expression* parse_prefix(void)
|
|
{
|
|
struct expression* parse_primary(void)
|
|
{
|
|
struct expression* retval;
|
|
|
|
switch (tokenkind)
|
|
{
|
|
case tk_identifier:
|
|
{
|
|
struct string* name =
|
|
new_string(buffer.data);
|
|
|
|
retval = new_variable_expression(name);
|
|
next_token();
|
|
|
|
free_string(name);
|
|
break;
|
|
}
|
|
|
|
case tk_literal:
|
|
{
|
|
struct value* value =
|
|
scan(buffer.data);
|
|
|
|
retval = new_literal_expression(value);
|
|
|
|
next_token();
|
|
|
|
free_value(value);
|
|
break;
|
|
}
|
|
|
|
case tk_oparen:
|
|
{
|
|
next_token();
|
|
|
|
retval = parse_root();
|
|
|
|
if (tokenkind != tk_cparen)
|
|
{
|
|
struct string* message =
|
|
new_string_from_fmt(
|
|
"unexpected '%s'",
|
|
tokennames[tokenkind]);
|
|
|
|
retval = new_syntax_error_expression(message, retval);
|
|
|
|
free_string(message);
|
|
}
|
|
|
|
next_token();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
struct string* message =
|
|
new_string_from_fmt(
|
|
"unexpected '%s'",
|
|
tokennames[tokenkind]);
|
|
|
|
retval = new_syntax_error_expression(message, NULL);
|
|
|
|
free_string(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
switch (tokenkind)
|
|
{
|
|
case tk_emark:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* sub =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_logical_not_expression(sub);
|
|
|
|
free_expression(sub);
|
|
|
|
return retval;
|
|
}
|
|
|
|
case tk_plus:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* sub =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_positive_expression(sub);
|
|
|
|
free_expression(sub);
|
|
|
|
return retval;
|
|
}
|
|
|
|
case tk_minus:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* sub =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_negative_expression(sub);
|
|
|
|
free_expression(sub);
|
|
|
|
return retval;
|
|
}
|
|
|
|
default:
|
|
return parse_primary();
|
|
}
|
|
}
|
|
|
|
struct expression* left = parse_prefix();
|
|
|
|
again: switch (tokenkind)
|
|
{
|
|
case tk_plus:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_add, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_minus:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_subtract, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_asterisk:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_multiply, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_slash:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_prefix();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_divide, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* left = parse_arithmetic();
|
|
|
|
again: switch (tokenkind)
|
|
{
|
|
case tk_less_than:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_arithmetic();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_less_than, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_less_than_eq:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_arithmetic();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_less_than_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_greater_than:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_arithmetic();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_greater_than, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_greater_than_eq:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_arithmetic();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_greater_than_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* left = parse_comparision();
|
|
|
|
again: switch (tokenkind)
|
|
{
|
|
case tk_equalsequals:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_comparision();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_emarkequals:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_comparision();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_not_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* left = parse_equality();
|
|
|
|
again: switch (tokenkind)
|
|
{
|
|
case tk_vbarvbar:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_equality();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_logical_or, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
case tk_ampersandampersand:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_equality();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_logical_and, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* center = parse_logicals();
|
|
|
|
if (tokenkind == tk_qmark)
|
|
{
|
|
next_token();
|
|
|
|
struct expression* left = parse_logicals();
|
|
|
|
next_token();
|
|
|
|
struct expression* right = parse_logicals();
|
|
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
return center;
|
|
}
|
|
}
|
|
|
|
struct expression* left = parse_ternary();
|
|
|
|
if (tokenkind == tk_equals)
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right = parse_assign();
|
|
|
|
struct expression* retval = new_binary_expression(ek_assign, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
return retval;
|
|
}
|
|
else
|
|
{
|
|
return left;
|
|
}
|
|
}
|
|
|
|
struct expression* left = parse_assign();
|
|
|
|
again: switch (tokenkind)
|
|
{
|
|
case tk_comma:
|
|
{
|
|
next_token();
|
|
|
|
struct expression* right = parse_assign();
|
|
|
|
struct expression* retval = new_binary_expression(ek_comma, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
return parse_comma();
|
|
}
|
|
|
|
struct expression* root = parse_root();
|
|
|
|
if (tokenkind != tk_EOF)
|
|
{
|
|
struct string* message = new_string_from_fmt(
|
|
"expected EOF, unexpected '%s'", tokennames[tokenkind]);
|
|
|
|
struct expression* error = new_syntax_error_expression(message, root);
|
|
|
|
free_expression(root);
|
|
|
|
root = error;
|
|
|
|
free_string(message);
|
|
}
|
|
|
|
free(buffer.data);
|
|
|
|
return root;
|
|
}
|
|
|
|
struct value** evaluate_lvalue(
|
|
struct expression* expression,
|
|
struct scope* scope)
|
|
{
|
|
switch (expression->kind)
|
|
{
|
|
case ek_syntax_error: assert(0); break;
|
|
|
|
case ek_variable:
|
|
{
|
|
return scope_lookup(scope, expression->string);
|
|
}
|
|
|
|
case ek_literal: TODO; break;
|
|
|
|
case ek_add: TODO; break;
|
|
case ek_subtract: TODO; break;
|
|
case ek_multiply: TODO; break;
|
|
case ek_divide: TODO; break;
|
|
|
|
case ek_positive: TODO; break;
|
|
case ek_negative: TODO; break;
|
|
|
|
case ek_greater_than: TODO; break;
|
|
case ek_greater_than_equal_to: TODO; break;
|
|
case ek_less_than: TODO; break;
|
|
case ek_less_than_equal_to: TODO; break;
|
|
|
|
case ek_equal_to: TODO; break;
|
|
case ek_not_equal_to: TODO; break;
|
|
|
|
case ek_logical_not: TODO; break;
|
|
case ek_logical_and: TODO; break;
|
|
case ek_logical_or: TODO; break;
|
|
|
|
case ek_ternary: TODO; break;
|
|
|
|
case ek_assign:
|
|
{
|
|
TODO;
|
|
break;
|
|
};
|
|
|
|
case ek_comma:
|
|
{
|
|
TODO;
|
|
break;
|
|
};
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct value* evaluate(
|
|
struct expression* expression,
|
|
struct scope* scope)
|
|
{
|
|
struct value* retval = NULL;
|
|
|
|
switch (expression->kind)
|
|
{
|
|
case ek_syntax_error: assert(0); break;
|
|
|
|
case ek_variable:
|
|
{
|
|
struct value* val = *scope_lookup(scope, expression->string);
|
|
|
|
if (val)
|
|
{
|
|
retval = inc_value(val);
|
|
}
|
|
else
|
|
{
|
|
retval = new_value_from_int(0);
|
|
}
|
|
|
|
break;
|
|
};
|
|
|
|
case ek_literal:
|
|
{
|
|
retval = inc_value(expression->value);
|
|
break;
|
|
}
|
|
|
|
case ek_add:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_add(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
mpq_clear(q);
|
|
break;
|
|
}
|
|
|
|
case ek_subtract:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_sub(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
mpq_clear(q);
|
|
break;
|
|
}
|
|
|
|
case ek_multiply:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_mul(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
mpq_clear(q);
|
|
break;
|
|
}
|
|
|
|
case ek_divide:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_div(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
mpq_clear(q);
|
|
break;
|
|
}
|
|
|
|
case ek_positive:
|
|
{
|
|
retval = evaluate(expression->center, scope);
|
|
break;
|
|
}
|
|
|
|
case ek_negative:
|
|
{
|
|
struct value* sub = evaluate(expression->center, scope);
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_neg(q, sub->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
free_value(sub);
|
|
|
|
mpq_clear(q);
|
|
break;
|
|
}
|
|
|
|
case ek_greater_than:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) > 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_greater_than_equal_to:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) >= 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_less_than:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) < 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_less_than_equal_to:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) <= 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_equal_to:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) == 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_not_equal_to:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) != 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_logical_not:
|
|
{
|
|
struct value* sub = evaluate(expression->center, scope);
|
|
|
|
retval = new_value_from_int(mpq_sgn(sub->mpq) == 0);
|
|
|
|
free_value(sub);
|
|
break;
|
|
}
|
|
|
|
case ek_logical_and:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(
|
|
mpq_sgn(left->mpq) != 0 && mpq_sgn(right->mpq) != 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_logical_or:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
retval = new_value_from_int(
|
|
mpq_sgn(left->mpq) != 0 || mpq_sgn(right->mpq) != 0);
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_ternary: TODO; break;
|
|
|
|
case ek_assign:
|
|
{
|
|
struct value** lvalue = evaluate_lvalue(expression->left, scope);
|
|
|
|
retval = evaluate(expression->right, scope);
|
|
|
|
free_value(*lvalue), *lvalue = inc_value(retval);
|
|
|
|
break;
|
|
};
|
|
|
|
case ek_comma:
|
|
{
|
|
free_value(evaluate(expression->left, scope));
|
|
|
|
retval = evaluate(expression->right, scope);
|
|
|
|
break;
|
|
};
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
void print_mpz(const mpz_t x_ro, const char* digits[10])
|
|
{
|
|
assert(mpz_sgn(x_ro) > 0);
|
|
|
|
mpz_t x, d, b;
|
|
|
|
mpz_init(x), mpz_init(d), mpz_init(b);
|
|
|
|
mpz_set(x, x_ro);
|
|
|
|
mpz_set_ui(b, 10);
|
|
|
|
size_t n = mpz_sizeinbase(x, 10);
|
|
|
|
unsigned *buffer = malloc(sizeof(*buffer) * n);
|
|
unsigned *moving = buffer;
|
|
|
|
while (mpz_sgn(x))
|
|
{
|
|
mpz_fdiv_qr(x, d, x, b);
|
|
|
|
assert(mpz_fits_uint_p(d));
|
|
|
|
unsigned int diu = mpz_get_ui(d);
|
|
|
|
assert(diu < 10);
|
|
|
|
*moving++ = diu;
|
|
}
|
|
|
|
while (moving > buffer)
|
|
{
|
|
printf("%s", digits[*--moving]);
|
|
}
|
|
|
|
free(buffer);
|
|
|
|
mpz_clear(x), mpz_clear(d), mpz_clear(b);
|
|
}
|
|
|
|
void print(struct value* this)
|
|
{
|
|
mpq_t v;
|
|
|
|
mpq_init(v);
|
|
|
|
mpq_set(v, this->mpq);
|
|
|
|
if (mpq_sgn(v) == 0)
|
|
{
|
|
putchar('0');
|
|
}
|
|
else
|
|
{
|
|
if (mpq_sgn(v) < 0)
|
|
{
|
|
putchar('-');
|
|
|
|
mpq_abs(v, v);
|
|
}
|
|
|
|
mpz_t q;
|
|
|
|
mpz_init(q);
|
|
|
|
mpz_fdiv_q(q, mpq_numref(v), mpq_denref(v));
|
|
|
|
if (mpz_sgn(q) > 0)
|
|
{
|
|
print_mpz(q,
|
|
(const char*[10]){"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"});
|
|
|
|
putchar(' ');
|
|
}
|
|
|
|
mpq_t qq;
|
|
|
|
mpq_init(qq);
|
|
|
|
mpq_set_z(qq, q);
|
|
|
|
mpq_sub(v, v, qq);
|
|
|
|
if (mpq_sgn(v) > 0)
|
|
{
|
|
print_mpz(mpq_numref(v),
|
|
(const char*[10]){"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"});
|
|
|
|
putchar('/');
|
|
|
|
print_mpz(mpq_denref(v),
|
|
(const char*[10]){"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉"});
|
|
}
|
|
|
|
mpq_clear(qq);
|
|
|
|
mpz_clear(q);
|
|
}
|
|
|
|
mpq_clear(v);
|
|
|
|
puts("");
|
|
}
|
|
|
|
void print_syntax_error(
|
|
const struct expression* this)
|
|
{
|
|
assert(this->kind == ek_syntax_error);
|
|
|
|
printf("syntax error: %s\n", this->string->data);
|
|
}
|
|
|
|
bool foreach_syntax_error(
|
|
struct expression* exp,
|
|
void (*callback)(
|
|
const struct expression*))
|
|
{
|
|
bool retval = false;
|
|
|
|
if (exp->kind == ek_syntax_error)
|
|
{
|
|
callback(exp);
|
|
|
|
retval = true;
|
|
}
|
|
|
|
if (exp->center && foreach_syntax_error(exp->center, callback))
|
|
{
|
|
retval = true;
|
|
}
|
|
|
|
if (exp->left && foreach_syntax_error(exp->left, callback))
|
|
{
|
|
retval = true;
|
|
}
|
|
|
|
if (exp->right && foreach_syntax_error(exp->right, callback))
|
|
{
|
|
retval = true;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
int main(int argc, char* const* argv)
|
|
{
|
|
parse_args(argc, argv);
|
|
|
|
if (command)
|
|
{
|
|
struct scope* scope = new_scope();
|
|
|
|
struct expression* expression = parse(command);
|
|
|
|
bool any_syntax_errors = foreach_syntax_error(expression,
|
|
print_syntax_error);
|
|
|
|
if (!any_syntax_errors)
|
|
{
|
|
struct value* value = evaluate(expression, scope);
|
|
|
|
print(value);
|
|
|
|
free_value(value);
|
|
}
|
|
|
|
free_expression(expression);
|
|
|
|
free_scope(scope);
|
|
}
|
|
else
|
|
{
|
|
struct scope* scope = new_scope();
|
|
|
|
for (char* line; (line = readline(">>> ")); free(line))
|
|
{
|
|
if (!*line) continue;
|
|
|
|
add_history(line);
|
|
|
|
struct expression* expression = parse(line);
|
|
|
|
struct value* value = evaluate(expression, scope);
|
|
|
|
print(value);
|
|
|
|
free_value(value);
|
|
|
|
free_expression(expression);
|
|
}
|
|
|
|
free_scope(scope);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|