3250 lines
72 KiB
C
3250 lines
72 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 CHECK assert(!"CHECK");
|
|
|
|
#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_va(const char* fmt, va_list va)
|
|
{
|
|
struct string* this = malloc(sizeof(*this));
|
|
|
|
int x = vasprintf(&this->data, fmt, va);
|
|
|
|
if (x < 0)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct string* new_string_from_fmt(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
struct string* this = new_string_from_fmt_va(fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return this;
|
|
}
|
|
|
|
struct string* inc_string(struct string* this)
|
|
{
|
|
if (this)
|
|
this->refcount++;
|
|
|
|
return this;
|
|
}
|
|
|
|
int compare_strings(const struct string* a, const struct string* b)
|
|
{
|
|
return strcmp(a->data, b->data);
|
|
}
|
|
|
|
int compare_strings_vv(const void* a, const void* b)
|
|
{
|
|
return compare_strings(
|
|
(const struct string*) a,
|
|
(const struct string*) b);
|
|
}
|
|
|
|
void free_string(struct string* this)
|
|
{
|
|
if (this && !--this->refcount)
|
|
{
|
|
free(this->data);
|
|
free(this);
|
|
}
|
|
}
|
|
|
|
void free_string_v(void* ptr)
|
|
{
|
|
free_string((struct string*) ptr);
|
|
}
|
|
|
|
struct stringset
|
|
{
|
|
struct avl_tree_t* tree;
|
|
unsigned refcount;
|
|
};
|
|
|
|
struct stringset* new_stringset(void)
|
|
{
|
|
struct stringset* this = malloc(sizeof(*this));
|
|
|
|
this->tree = avl_alloc_tree(compare_strings_vv, free_string_v);
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
bool stringset_add(struct stringset* this, struct string* new)
|
|
{
|
|
bool is_new;
|
|
|
|
struct avl_node_t* node = avl_insert(this->tree, new);
|
|
|
|
if (node)
|
|
{
|
|
inc_string(new);
|
|
|
|
is_new = true;
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
}
|
|
|
|
return is_new;
|
|
}
|
|
|
|
bool stringset_update(struct stringset* this, const struct stringset* updateme)
|
|
{
|
|
bool is_new = false;
|
|
|
|
for (struct avl_node_t* i = updateme->tree->head; i; i = i->next)
|
|
{
|
|
struct avl_node_t* node = avl_insert(this->tree, i->item);
|
|
|
|
if (node)
|
|
{
|
|
inc_string(i->item);
|
|
|
|
is_new = true;
|
|
}
|
|
else if (errno == EEXIST)
|
|
{
|
|
;
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
}
|
|
}
|
|
|
|
return is_new;
|
|
}
|
|
|
|
struct stringset* inc_stringset(struct stringset* this)
|
|
{
|
|
if (this)
|
|
this->refcount++;
|
|
|
|
return this;
|
|
}
|
|
|
|
void stringset_println(const struct stringset* this)
|
|
{
|
|
for (struct avl_node_t* i = this->tree->head; i; i = i->next)
|
|
{
|
|
const struct string* str = i->item;
|
|
|
|
printf("%s\n", str->data);
|
|
}
|
|
}
|
|
|
|
void free_stringset(struct stringset* this)
|
|
{
|
|
if (this && !--this->refcount)
|
|
{
|
|
avl_free_tree(this->tree);
|
|
|
|
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,
|
|
ek_integer_divide,
|
|
ek_remainder,
|
|
ek_exponent,
|
|
|
|
// bitwise operator:
|
|
ek_leftbitshift,
|
|
ek_rightbitshift,
|
|
|
|
// 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;
|
|
|
|
unsigned column;
|
|
|
|
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(
|
|
unsigned column,
|
|
struct string* error_message)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_syntax_error;
|
|
|
|
this->column = column;
|
|
this->string = inc_string(error_message);
|
|
this->center = NULL;
|
|
this->left = NULL;
|
|
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* new_ternary_expression(
|
|
struct expression* center,
|
|
struct expression* left,
|
|
struct expression* right)
|
|
{
|
|
struct expression* this = malloc(sizeof(*this));
|
|
|
|
this->kind = ek_ternary;
|
|
this->string = NULL;
|
|
this->center = inc_expression(center);
|
|
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);
|
|
}
|
|
}
|
|
|
|
enum value_kind
|
|
{
|
|
vk_number,
|
|
vk_error,
|
|
};
|
|
|
|
struct value
|
|
{
|
|
enum value_kind kind;
|
|
|
|
struct stringset* errors;
|
|
|
|
mpq_t mpq;
|
|
|
|
unsigned refcount;
|
|
};
|
|
|
|
struct value* new_error_value(struct stringset* errors)
|
|
{
|
|
struct value* this = malloc(sizeof(*this));
|
|
|
|
this->kind = vk_error;
|
|
|
|
this->errors = inc_stringset(errors);
|
|
|
|
mpq_init(this->mpq);
|
|
|
|
this->refcount = 1;
|
|
|
|
return this;
|
|
}
|
|
|
|
struct value* new_error_value_from_fmt(const char* fmt, ...)
|
|
{
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
|
|
struct string* message = new_string_from_fmt_va(fmt, va);
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_add(set, message);
|
|
|
|
struct value* this = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
|
|
free_string(message);
|
|
|
|
va_end(va);
|
|
|
|
return this;
|
|
}
|
|
|
|
struct value* new_error_value_from_union(
|
|
const struct value* left,
|
|
const struct value* right)
|
|
{
|
|
assert(left->kind == vk_error);
|
|
assert(right->kind == vk_error);
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
struct value* retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
|
|
return retval;
|
|
}
|
|
|
|
struct value* new_value_from_int(int x)
|
|
{
|
|
struct value* this = malloc(sizeof(*this));
|
|
|
|
this->kind = vk_number;
|
|
|
|
this->errors = NULL;
|
|
|
|
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));
|
|
|
|
this->kind = vk_number;
|
|
|
|
this->errors = NULL;
|
|
|
|
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_stringset(this->errors);
|
|
|
|
free(this);
|
|
}
|
|
}
|
|
|
|
struct value* scan(const char* text)
|
|
{
|
|
const char* moving = text;
|
|
|
|
const char* digits = "0123456789";
|
|
|
|
unsigned ibase = 10;
|
|
|
|
if (text[0] == '0' && text[1] == 'b')
|
|
{
|
|
digits = "01";
|
|
ibase = 2;
|
|
moving += 2;
|
|
}
|
|
else if (text[0] == '0' && text[1] == 'x')
|
|
{
|
|
digits = "0123456789ABCDEF";
|
|
ibase = 16;
|
|
moving += 2;
|
|
}
|
|
|
|
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, ibase, 1);
|
|
|
|
while ('_' == *moving || (*moving && index(digits, toupper(*moving))))
|
|
{
|
|
if ('_' == *moving)
|
|
{
|
|
moving++;
|
|
}
|
|
else
|
|
{
|
|
mpq_set_si(tmp, index(digits, toupper(*moving++)) - digits, 1);
|
|
|
|
mpq_mul(value, value, base);
|
|
mpq_add(value, value, tmp);
|
|
}
|
|
}
|
|
|
|
while ('_' == *moving)
|
|
{
|
|
moving++;
|
|
}
|
|
|
|
if (*moving == '.')
|
|
{
|
|
mpq_t factor; mpq_init(factor);
|
|
|
|
moving++;
|
|
|
|
mpq_set_si(factor, 1, ibase);
|
|
|
|
while ('_' == *moving || (*moving && index(digits, toupper(*moving))))
|
|
{
|
|
if ('_' == *moving)
|
|
{
|
|
moving++;
|
|
}
|
|
else
|
|
{
|
|
mpq_set_si(tmp, index(digits, toupper(*moving++)) - digits, 1);
|
|
|
|
mpq_mul(tmp, factor, tmp);
|
|
|
|
mpq_add(value, value, tmp);
|
|
|
|
mpq_div(factor, factor, base);
|
|
}
|
|
}
|
|
|
|
mpq_clear(factor);
|
|
}
|
|
|
|
while ('_' == *moving)
|
|
{
|
|
moving++;
|
|
}
|
|
|
|
assert(*moving == '\0');
|
|
|
|
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);
|
|
}
|
|
|
|
enum token
|
|
{
|
|
t_uninitialized,
|
|
|
|
t_error,
|
|
|
|
// primary:
|
|
t_identifier,
|
|
t_literal,
|
|
t_binary,
|
|
t_hexadecimal,
|
|
|
|
// brakets:
|
|
t_oparen,
|
|
t_cparen,
|
|
|
|
// arithmetic operators:
|
|
t_plus,
|
|
t_minus,
|
|
t_asterisk,
|
|
t_slash,
|
|
t_percent,
|
|
t_slash_slash,
|
|
t_asterisk_asterisk,
|
|
|
|
// comparision operators:
|
|
t_lessthan,
|
|
t_lessthan_equals,
|
|
t_lessthan_lessthan,
|
|
|
|
t_greaterthan,
|
|
t_greaterthan_equals,
|
|
t_greaterthan_greaterthan,
|
|
|
|
t_emark_equals,
|
|
t_equals_equals,
|
|
|
|
// logical operators:
|
|
t_vbar_vbar,
|
|
t_ampersand_ampersand,
|
|
|
|
// misc:
|
|
t_emark,
|
|
t_qmark,
|
|
t_colon,
|
|
t_equals,
|
|
t_comma,
|
|
|
|
t_EOF,
|
|
|
|
number_of_tokens,
|
|
};
|
|
|
|
static const char* const tokennames[number_of_tokens] = {
|
|
[t_EOF] = "EOF",
|
|
|
|
[t_identifier] = "identifier",
|
|
[t_literal] = "literal",
|
|
[t_binary] = "binary-literal",
|
|
[t_hexadecimal] = "hexadecimal-literal",
|
|
[t_oparen] = "open parentheses",
|
|
[t_cparen] = "close parentheses",
|
|
[t_plus] = "plus",
|
|
[t_minus] = "minus",
|
|
[t_asterisk] = "asterisk",
|
|
[t_asterisk_asterisk] = "double-asterisk",
|
|
[t_percent] = "percent",
|
|
[t_slash] = "slash",
|
|
[t_slash_slash] = "double-slash",
|
|
[t_lessthan] = "less-than",
|
|
[t_lessthan_equals] = "less-than-or-equal-to",
|
|
[t_greaterthan] = "greater-than",
|
|
[t_greaterthan_equals] = "greater-than-or-equal-to",
|
|
[t_emark_equals] = "not-equal-to",
|
|
[t_equals_equals] = "equal-to",
|
|
[t_vbar_vbar] = "logical-or",
|
|
[t_ampersand_ampersand] = "logical-and",
|
|
[t_emark] = "exclamation mark",
|
|
[t_qmark] = "question mark",
|
|
[t_colon] = "colon",
|
|
[t_equals] = "assignment",
|
|
[t_comma] = "comma",
|
|
};
|
|
|
|
struct tokenizer
|
|
{
|
|
const char* text;
|
|
|
|
unsigned start_index;
|
|
unsigned index;
|
|
|
|
enum token token;
|
|
|
|
struct buffer {
|
|
char* data;
|
|
size_t n, cap;
|
|
} buffer;
|
|
};
|
|
|
|
struct tokenizer* new_tokenizer(const char* text)
|
|
{
|
|
struct tokenizer* this = malloc(sizeof(*this));
|
|
|
|
this->text = text;
|
|
|
|
this->start_index = 0;
|
|
this->index = 0;
|
|
|
|
this->token = t_uninitialized;
|
|
|
|
this->buffer.data = NULL;
|
|
this->buffer.n = 0;
|
|
this->buffer.cap = 0;
|
|
|
|
return this;
|
|
}
|
|
|
|
void tokenizer_append_char(
|
|
struct tokenizer* this,
|
|
char code)
|
|
{
|
|
if (this->buffer.n == this->buffer.cap)
|
|
{
|
|
this->buffer.cap = this->buffer.cap << 1 ?: 1;
|
|
|
|
this->buffer.data = realloc(
|
|
this->buffer.data,
|
|
sizeof(*this->buffer.data) * this->buffer.cap);
|
|
}
|
|
|
|
this->buffer.data[this->buffer.n++] = code;
|
|
}
|
|
|
|
enum tokenizer_state {
|
|
ts_error,
|
|
|
|
ts_EOF,
|
|
|
|
ts_literal,
|
|
|
|
ts_identifier,
|
|
|
|
ts_equals,
|
|
ts_comma,
|
|
ts_slash,
|
|
ts_plus,
|
|
ts_minus,
|
|
ts_qmark,
|
|
ts_emark,
|
|
ts_colon,
|
|
ts_percent,
|
|
ts_asterisk,
|
|
ts_asterisk_asterisk,
|
|
ts_lessthan,
|
|
ts_lessthan_equals,
|
|
ts_lessthan_lessthan,
|
|
ts_greaterthan,
|
|
ts_greaterthan_equals,
|
|
ts_greaterthan_greaterthan,
|
|
ts_equals_equals,
|
|
ts_slash_slash,
|
|
|
|
ts_oparen,
|
|
ts_cparen,
|
|
|
|
ts_vbar_vbar,
|
|
|
|
ts_start,
|
|
|
|
ts_reading_literal_prefix,
|
|
ts_reading_literal,
|
|
ts_reading_literal2,
|
|
ts_reading_literal_binary,
|
|
ts_reading_literal_binary2,
|
|
ts_reading_literal_hexadecimal,
|
|
ts_reading_literal_hexadecimal2,
|
|
|
|
ts_reading_identifier,
|
|
|
|
ts_reading_equals,
|
|
ts_reading_equals_equals,
|
|
ts_reading_slash,
|
|
ts_reading_slash_slash,
|
|
ts_reading_comma,
|
|
ts_reading_plus,
|
|
ts_reading_minus,
|
|
ts_reading_qmark,
|
|
ts_reading_emark,
|
|
ts_reading_colon,
|
|
ts_reading_asterisk,
|
|
ts_reading_asterisk_asterisk,
|
|
ts_reading_percent,
|
|
ts_reading_lessthan,
|
|
ts_reading_lessthan_equals,
|
|
ts_reading_lessthan_lessthan,
|
|
ts_reading_greaterthan,
|
|
ts_reading_greaterthan_equals,
|
|
ts_reading_greaterthan_greaterthan,
|
|
|
|
ts_reading_oparen,
|
|
ts_reading_cparen,
|
|
|
|
ts_reading_vbar,
|
|
ts_reading_vbar_vbar,
|
|
|
|
number_of_tokenizer_states,
|
|
} tokenizer_lookup[number_of_tokenizer_states][128] = {
|
|
#define ANY 0 ... 127
|
|
|
|
// skip whitespace:
|
|
[ts_start][' '] = ts_start,
|
|
|
|
// EOF token:
|
|
[ts_start][0] = ts_EOF,
|
|
|
|
// binary: "0b" ['_', '0', '1']+ ('.' ['_', '0', '1']*)?
|
|
// hexadecimal: "0x" [_0-9a-fA-F]+ (.[_0-9a-fA-F]*)?
|
|
// literal: [0-9]+ [_0-9]* (. [_0-9]*)?
|
|
[ts_start]['0'] = ts_reading_literal_prefix,
|
|
[ts_reading_literal_prefix][ANY] = ts_literal,
|
|
[ts_reading_literal_prefix]['b'] = ts_reading_literal_binary,
|
|
[ts_reading_literal_binary][ ANY ] = ts_literal,
|
|
[ts_reading_literal_binary]['0' ... '1'] = ts_reading_literal_binary,
|
|
[ts_reading_literal_binary][ '_' ] = ts_reading_literal_binary,
|
|
[ts_reading_literal_binary][ '.' ] = ts_reading_literal_binary2,
|
|
[ts_reading_literal_binary2][ ANY ] = ts_literal,
|
|
[ts_reading_literal_binary2][ '_' ] = ts_reading_literal_binary2,
|
|
[ts_reading_literal_binary2]['0' ... '1'] = ts_reading_literal_binary2,
|
|
[ts_reading_literal_prefix]['x'] = ts_reading_literal_hexadecimal,
|
|
[ts_reading_literal_hexadecimal][ ANY ] = ts_literal,
|
|
[ts_reading_literal_hexadecimal]['0' ... '9'] = ts_reading_literal_hexadecimal,
|
|
[ts_reading_literal_hexadecimal]['a' ... 'f'] = ts_reading_literal_hexadecimal,
|
|
[ts_reading_literal_hexadecimal]['A' ... 'F'] = ts_reading_literal_hexadecimal,
|
|
[ts_reading_literal_hexadecimal][ '_' ] = ts_reading_literal_hexadecimal,
|
|
[ts_reading_literal_hexadecimal][ '.' ] = ts_reading_literal_hexadecimal2,
|
|
[ts_reading_literal_hexadecimal2][ ANY ] = ts_literal,
|
|
[ts_reading_literal_hexadecimal2][ '_' ] = ts_reading_literal_hexadecimal2,
|
|
[ts_reading_literal_hexadecimal2]['0' ... '9'] = ts_reading_literal_hexadecimal2,
|
|
[ts_reading_literal_hexadecimal2]['a' ... 'f'] = ts_reading_literal_hexadecimal2,
|
|
[ts_reading_literal_hexadecimal2]['A' ... 'F'] = ts_reading_literal_hexadecimal2,
|
|
[ts_reading_literal_prefix]['_'] = ts_reading_literal,
|
|
[ts_reading_literal_prefix]['.'] = ts_reading_literal2,
|
|
[ts_reading_literal_prefix]['0' ... '9'] = ts_reading_literal,
|
|
[ts_start]['1' ... '9'] = ts_reading_literal,
|
|
[ts_reading_literal][ ANY ] = ts_literal,
|
|
[ts_reading_literal][ '_' ] = ts_reading_literal,
|
|
[ts_reading_literal]['0' ... '9'] = ts_reading_literal,
|
|
[ts_reading_literal]['a' ... 'z'] = ts_error,
|
|
[ts_reading_literal][ '.' ] = ts_reading_literal2,
|
|
[ts_reading_literal2][ ANY ] = ts_literal,
|
|
[ts_reading_literal2][ '_' ] = ts_reading_literal2,
|
|
[ts_reading_literal2]['0' ... '9'] = ts_reading_literal2,
|
|
|
|
// identifiers:
|
|
[ts_start][ '_' ] = ts_reading_identifier,
|
|
[ts_start]['a' ... 'z'] = ts_reading_identifier,
|
|
[ts_reading_identifier][ ANY ] = ts_identifier,
|
|
[ts_reading_identifier][ '_' ] = ts_reading_identifier,
|
|
[ts_reading_identifier]['0' ... '9'] = ts_reading_identifier,
|
|
[ts_reading_identifier]['a' ... 'z'] = ts_reading_identifier,
|
|
|
|
// symbols:
|
|
|
|
[ts_start]['+'] = ts_reading_plus, [ts_reading_plus][ANY] = ts_plus,
|
|
|
|
[ts_start]['-'] = ts_reading_minus, [ts_reading_minus][ANY] = ts_minus,
|
|
|
|
[ts_start]['%'] = ts_reading_percent, [ts_reading_percent][ANY] = ts_percent,
|
|
|
|
[ts_start]['?'] = ts_reading_qmark, [ts_reading_qmark][ANY] = ts_qmark,
|
|
|
|
[ts_start]['!'] = ts_reading_emark, [ts_reading_emark][ANY] = ts_emark,
|
|
|
|
[ts_start][':'] = ts_reading_colon, [ts_reading_colon][ANY] = ts_colon,
|
|
|
|
[ts_start][','] = ts_reading_comma, [ts_reading_comma][ANY] = ts_comma,
|
|
|
|
[ts_start]['('] = ts_reading_oparen, [ts_reading_oparen][ANY] = ts_oparen,
|
|
[ts_start][')'] = ts_reading_cparen, [ts_reading_cparen][ANY] = ts_cparen,
|
|
|
|
// '*' or '**'
|
|
[ts_start]['*'] = ts_reading_asterisk,
|
|
[ts_reading_asterisk][ANY] = ts_asterisk,
|
|
[ts_reading_asterisk]['*'] = ts_reading_asterisk_asterisk,
|
|
[ts_reading_asterisk_asterisk][ANY] = ts_asterisk_asterisk,
|
|
|
|
// '/' or '//':
|
|
[ts_start]['/'] = ts_reading_slash,
|
|
[ts_reading_slash][ANY] = ts_slash,
|
|
[ts_reading_slash]['/'] = ts_reading_slash_slash,
|
|
[ts_reading_slash_slash][ANY] = ts_slash_slash,
|
|
|
|
// '=' or '==':
|
|
[ts_start]['='] = ts_reading_equals,
|
|
[ts_reading_equals][ANY] = ts_equals,
|
|
[ts_reading_equals]['='] = ts_reading_equals_equals,
|
|
[ts_reading_equals_equals][ANY] = ts_equals_equals,
|
|
|
|
// '<' or '<=' or '<<':
|
|
[ts_start]['<'] = ts_reading_lessthan,
|
|
[ts_reading_lessthan][ANY] = ts_lessthan,
|
|
[ts_reading_lessthan]['='] = ts_reading_lessthan_equals,
|
|
[ts_reading_lessthan_equals][ANY] = ts_lessthan_equals,
|
|
[ts_reading_lessthan]['<'] = ts_reading_lessthan_lessthan,
|
|
[ts_reading_lessthan_lessthan][ANY] = ts_lessthan_lessthan,
|
|
|
|
// '>' or '>=' or '>>':
|
|
[ts_start]['>'] = ts_reading_greaterthan,
|
|
[ts_reading_greaterthan][ANY] = ts_greaterthan,
|
|
[ts_reading_greaterthan]['='] = ts_reading_greaterthan_equals,
|
|
[ts_reading_greaterthan_equals][ANY] = ts_greaterthan_equals,
|
|
[ts_reading_greaterthan]['>'] = ts_reading_greaterthan_greaterthan,
|
|
[ts_reading_greaterthan_greaterthan][ANY] = ts_greaterthan_greaterthan,
|
|
|
|
// '||':
|
|
[ts_start]['|'] = ts_reading_vbar,
|
|
[ts_reading_vbar]['|'] = ts_reading_vbar_vbar,
|
|
[ts_reading_vbar_vbar][ANY] = ts_vbar_vbar,
|
|
};
|
|
|
|
void tokenizer_next(
|
|
struct tokenizer* this)
|
|
{
|
|
this->buffer.n = 0;
|
|
|
|
this->start_index = this->index;
|
|
|
|
enum tokenizer_state state = ts_start;
|
|
|
|
while (state >= ts_start)
|
|
{
|
|
assert(this->text[this->index] >= 0);
|
|
|
|
state = tokenizer_lookup[state][(uint8_t) this->text[this->index]];
|
|
|
|
if (state > ts_start)
|
|
{
|
|
tokenizer_append_char(this, this->text[this->index]);
|
|
|
|
this->index++;
|
|
}
|
|
|
|
if (state == ts_start)
|
|
{
|
|
this->buffer.n = 0;
|
|
|
|
this->index++;
|
|
|
|
this->start_index = this->index;
|
|
}
|
|
}
|
|
|
|
// for sake of the error message:
|
|
if (state == ts_error)
|
|
{
|
|
tokenizer_append_char(this, this->text[this->index]);
|
|
}
|
|
|
|
tokenizer_append_char(this, '\0');
|
|
|
|
switch (state)
|
|
{
|
|
case ts_error:
|
|
{
|
|
this->token = t_error;
|
|
break;
|
|
}
|
|
|
|
case ts_EOF:
|
|
{
|
|
this->token = t_EOF;
|
|
break;
|
|
}
|
|
|
|
case ts_literal:
|
|
{
|
|
this->token = t_literal;
|
|
break;
|
|
}
|
|
|
|
case ts_identifier:
|
|
{
|
|
this->token = t_identifier;
|
|
break;
|
|
}
|
|
|
|
case ts_equals:
|
|
{
|
|
this->token = t_equals;
|
|
break;
|
|
}
|
|
|
|
case ts_comma:
|
|
{
|
|
this->token = t_comma;
|
|
break;
|
|
}
|
|
|
|
case ts_plus:
|
|
{
|
|
this->token = t_plus;
|
|
break;
|
|
}
|
|
|
|
case ts_qmark:
|
|
{
|
|
this->token = t_qmark;
|
|
break;
|
|
}
|
|
|
|
case ts_minus:
|
|
{
|
|
this->token = t_minus;
|
|
break;
|
|
}
|
|
|
|
case ts_slash:
|
|
{
|
|
this->token = t_slash;
|
|
break;
|
|
}
|
|
|
|
case ts_equals_equals:
|
|
{
|
|
this->token = t_equals_equals;
|
|
break;
|
|
}
|
|
|
|
case ts_emark:
|
|
{
|
|
this->token = t_emark;
|
|
break;
|
|
}
|
|
|
|
case ts_oparen:
|
|
{
|
|
this->token = t_oparen;
|
|
break;
|
|
}
|
|
|
|
case ts_cparen:
|
|
{
|
|
this->token = t_cparen;
|
|
break;
|
|
}
|
|
|
|
case ts_percent:
|
|
{
|
|
this->token = t_percent;
|
|
break;
|
|
}
|
|
|
|
case ts_lessthan:
|
|
{
|
|
this->token = t_lessthan;
|
|
break;
|
|
}
|
|
|
|
case ts_lessthan_equals:
|
|
{
|
|
this->token = t_lessthan_equals;
|
|
break;
|
|
}
|
|
|
|
case ts_colon:
|
|
{
|
|
this->token = t_colon;
|
|
break;
|
|
}
|
|
|
|
case ts_asterisk:
|
|
{
|
|
this->token = t_asterisk;
|
|
break;
|
|
}
|
|
|
|
case ts_vbar_vbar:
|
|
{
|
|
this->token = t_vbar_vbar;
|
|
break;
|
|
}
|
|
|
|
case ts_slash_slash:
|
|
{
|
|
this->token = t_slash_slash;
|
|
break;
|
|
}
|
|
|
|
case ts_lessthan_lessthan:
|
|
{
|
|
this->token = t_lessthan_lessthan;
|
|
break;
|
|
}
|
|
|
|
case ts_greaterthan_greaterthan:
|
|
{
|
|
this->token = t_greaterthan_greaterthan;
|
|
break;
|
|
}
|
|
|
|
case ts_asterisk_asterisk:
|
|
{
|
|
this->token = t_asterisk_asterisk;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TODO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void free_tokenizer(
|
|
struct tokenizer* this)
|
|
{
|
|
free(this->buffer.data);
|
|
free(this);
|
|
}
|
|
|
|
struct string* make_unexpected_token_message(
|
|
struct tokenizer* tokenizer)
|
|
{
|
|
if (tokenizer->token == t_error)
|
|
{
|
|
return new_string_from_fmt(
|
|
"unexpected unknown token '%s'",
|
|
tokenizer->buffer.data);
|
|
}
|
|
else
|
|
{
|
|
assert(tokennames[tokenizer->token]);
|
|
|
|
return new_string_from_fmt(
|
|
"unexpected %s token",
|
|
tokennames[tokenizer->token]);
|
|
}
|
|
}
|
|
|
|
struct expression* parse_root(struct tokenizer* tokenizer);
|
|
|
|
struct expression* parse_primary(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* retval = NULL;
|
|
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_error:
|
|
{
|
|
struct string* message = new_string_from_fmt(
|
|
"unknown token '%s'", tokenizer->buffer.data);
|
|
|
|
retval = new_syntax_error_expression(
|
|
/* column: */ tokenizer->start_index + 1,
|
|
/* message: */ message);
|
|
|
|
tokenizer_next(tokenizer);
|
|
|
|
free_string(message);
|
|
break;
|
|
}
|
|
|
|
case t_literal:
|
|
{
|
|
struct value* value = scan(tokenizer->buffer.data);
|
|
|
|
retval = new_literal_expression(value);
|
|
|
|
tokenizer_next(tokenizer);
|
|
|
|
free_value(value);
|
|
break;
|
|
}
|
|
|
|
case t_hexadecimal:
|
|
{
|
|
TODO;
|
|
break;
|
|
}
|
|
|
|
case t_identifier:
|
|
{
|
|
struct string* name = new_string(tokenizer->buffer.data);
|
|
|
|
retval = new_variable_expression(name);
|
|
|
|
tokenizer_next(tokenizer);
|
|
|
|
free_string(name);
|
|
break;
|
|
}
|
|
|
|
case t_oparen:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* sub = parse_root(tokenizer);
|
|
|
|
if (sub->kind == ek_syntax_error)
|
|
{
|
|
retval = inc_expression(sub);
|
|
}
|
|
else if (tokenizer->token == t_cparen)
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
retval = inc_expression(sub);
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
}
|
|
|
|
free_expression(sub);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
struct string* message = make_unexpected_token_message(tokenizer);
|
|
|
|
retval = new_syntax_error_expression(
|
|
/* column: */ tokenizer->start_index + 1,
|
|
/* message: */ message);
|
|
|
|
tokenizer_next(tokenizer);
|
|
|
|
free_string(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(retval);
|
|
|
|
return retval;
|
|
}
|
|
|
|
struct expression* parse_prefix(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* retval = NULL;
|
|
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_emark:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* sub = parse_prefix(tokenizer);
|
|
|
|
if (sub->kind == ek_syntax_error)
|
|
{
|
|
retval = sub;
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
#if 0
|
|
struct expression* retval =
|
|
new_logical_not_expression(sub);
|
|
|
|
free_expression(sub);
|
|
|
|
return retval;
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case t_plus:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* sub = parse_prefix(tokenizer);
|
|
|
|
if (sub->kind == ek_syntax_error)
|
|
{
|
|
retval = sub;
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
#if 0
|
|
retval = new_positive_expression(sub);
|
|
|
|
free_expression(sub);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case t_minus:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* sub = parse_prefix(tokenizer);
|
|
|
|
if (sub->kind == ek_syntax_error)
|
|
{
|
|
retval = inc_expression(sub);
|
|
}
|
|
else
|
|
{
|
|
retval = new_negative_expression(sub);
|
|
}
|
|
|
|
free_expression(sub);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
retval = parse_primary(tokenizer);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(retval);
|
|
|
|
return retval;
|
|
}
|
|
|
|
struct expression* parse_exponent(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_prefix(tokenizer);
|
|
|
|
while (true
|
|
&& left->kind != ek_syntax_error
|
|
&& (tokenizer->token == t_asterisk_asterisk))
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_prefix(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_exponent, left, right);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_multiplicative(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_exponent(tokenizer);
|
|
|
|
while (true
|
|
&& left->kind != ek_syntax_error
|
|
&& (false
|
|
|| tokenizer->token == t_asterisk
|
|
|| tokenizer->token == t_slash
|
|
|| tokenizer->token == t_slash_slash
|
|
|| tokenizer->token == t_percent))
|
|
{
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_asterisk:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_exponent(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_multiply, left, right);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case t_slash:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_exponent(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_divide, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case t_slash_slash:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_exponent(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_integer_divide, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case t_percent:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_exponent(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_remainder, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_additive(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_multiplicative(tokenizer);
|
|
|
|
while (true
|
|
&& left->kind != ek_syntax_error
|
|
&& (false
|
|
|| tokenizer->token == t_plus
|
|
|| tokenizer->token == t_minus))
|
|
{
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_plus:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_multiplicative(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = right;
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_add, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case t_minus:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_multiplicative(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_subtract, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TODO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_shift(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_additive(tokenizer);
|
|
|
|
while (true
|
|
&& left->kind != ek_syntax_error
|
|
&& (false
|
|
|| tokenizer->token == t_lessthan_lessthan
|
|
|| tokenizer->token == t_greaterthan_greaterthan))
|
|
{
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_lessthan_lessthan:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_additive(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = right;
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_leftbitshift, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case t_greaterthan_greaterthan:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_additive(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_rightbitshift, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TODO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_comparision(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_shift(tokenizer);
|
|
|
|
while (true
|
|
&& left->kind != ek_syntax_error
|
|
&& (false
|
|
|| tokenizer->token == t_lessthan
|
|
|| tokenizer->token == t_lessthan_equals
|
|
|| tokenizer->token == t_greaterthan
|
|
|| tokenizer->token == t_greaterthan_equals))
|
|
{
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_lessthan:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_shift(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_less_than, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case t_lessthan_equals:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_additive(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_less_than_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case t_greaterthan:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_additive();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_greater_than, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
#endif
|
|
}
|
|
|
|
case t_greaterthan_equals:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
next_token();
|
|
|
|
struct expression* right =
|
|
parse_additive();
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_greater_than_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
|
|
goto again;
|
|
#endif
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_equality(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_comparision(tokenizer);
|
|
|
|
while (true
|
|
&& left->kind != ek_syntax_error
|
|
&& (false
|
|
|| tokenizer->token == t_equals_equals
|
|
|| tokenizer->token == t_emark_equals))
|
|
{
|
|
switch (tokenizer->token)
|
|
{
|
|
case t_equals_equals:
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_comparision(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(left);
|
|
|
|
left = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* retval =
|
|
new_binary_expression(ek_equal_to, left, right);
|
|
|
|
free_expression(left);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
free_expression(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case t_emark_equals:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_logical_and(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_equality(tokenizer);
|
|
|
|
while (tokenizer->token == t_ampersand_ampersand)
|
|
{
|
|
TODO;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_logical_or(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_logical_and(tokenizer);
|
|
|
|
while (tokenizer->token == t_vbar_vbar)
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_comparision(tokenizer);
|
|
|
|
struct expression* retval =
|
|
new_binary_expression(ek_logical_or, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_ternary(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* center = parse_logical_or(tokenizer);
|
|
|
|
while (true
|
|
&& center->kind != ek_syntax_error
|
|
&& tokenizer->token == t_qmark)
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* left = parse_root(tokenizer);
|
|
|
|
if (left->kind == ek_syntax_error)
|
|
{
|
|
free_expression(center);
|
|
|
|
center = inc_expression(left);
|
|
}
|
|
else if (tokenizer->token == t_colon)
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_logical_or(tokenizer);
|
|
|
|
if (right->kind == ek_syntax_error)
|
|
{
|
|
free_expression(center);
|
|
|
|
center = inc_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct expression* new = new_ternary_expression(center, left, right);
|
|
|
|
free_expression(center);
|
|
|
|
center = new;
|
|
}
|
|
|
|
free_expression(right);
|
|
}
|
|
else
|
|
{
|
|
struct string* message = make_unexpected_token_message(tokenizer);
|
|
|
|
struct expression* error = new_syntax_error_expression(
|
|
tokenizer->start_index + 1, message);
|
|
|
|
free_expression(center);
|
|
|
|
center = error;
|
|
|
|
tokenizer_next(tokenizer);
|
|
|
|
free_string(message);
|
|
}
|
|
|
|
free_expression(left);
|
|
}
|
|
|
|
return center;
|
|
}
|
|
|
|
struct expression* parse_assign(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_ternary(tokenizer);
|
|
|
|
if (tokenizer->token == t_equals)
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_assign(tokenizer);
|
|
|
|
struct expression* retval = new_binary_expression(ek_assign, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
return retval;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_comma(struct tokenizer* tokenizer)
|
|
{
|
|
struct expression* left = parse_assign(tokenizer);
|
|
|
|
while (tokenizer->token == t_comma)
|
|
{
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* right = parse_assign(tokenizer);
|
|
|
|
struct expression* retval = new_binary_expression(ek_comma, left, right);
|
|
|
|
free_expression(left);
|
|
free_expression(right);
|
|
|
|
left = retval;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
struct expression* parse_root(struct tokenizer* tokenizer)
|
|
{
|
|
return parse_comma(tokenizer);
|
|
}
|
|
|
|
struct expression* parse(const char* text)
|
|
{
|
|
struct tokenizer* tokenizer = new_tokenizer(text);
|
|
|
|
tokenizer_next(tokenizer);
|
|
|
|
struct expression* root = parse_root(tokenizer);
|
|
|
|
if (root->kind != ek_syntax_error && tokenizer->token != t_EOF)
|
|
{
|
|
struct string* message = make_unexpected_token_message(tokenizer);
|
|
|
|
struct expression* error = new_syntax_error_expression(
|
|
tokenizer->index + 1, message);
|
|
|
|
free_expression(root);
|
|
|
|
root = error;
|
|
|
|
free_string(message);
|
|
}
|
|
|
|
free_tokenizer(tokenizer);
|
|
|
|
return root;
|
|
}
|
|
|
|
#if 0
|
|
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_remainder: TODO; break;
|
|
|
|
case ek_assign:
|
|
{
|
|
TODO;
|
|
break;
|
|
};
|
|
|
|
case ek_comma:
|
|
{
|
|
TODO;
|
|
break;
|
|
};
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
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_error_value_from_fmt(
|
|
"error: use of undefined variable '%s'!",
|
|
expression->string->data);
|
|
}
|
|
|
|
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);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_unionnew_error_value_from_union
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_add(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_subtract:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO
|
|
// new_error_value_from_union
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
#if 0
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_sub(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
#endif
|
|
}
|
|
|
|
free_value(left);
|
|
|
|
free_value(right);
|
|
break;
|
|
}
|
|
|
|
case ek_multiply:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
#if 0
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_mul(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
#endif
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_integer_divide:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else
|
|
{
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_div(q, left->mpq, right->mpq);
|
|
|
|
mpz_tdiv_q(mpq_numref(q), mpq_numref(q), mpq_denref(q));
|
|
|
|
mpz_set_si(mpq_denref(q), 1);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_rightbitshift:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
retval = new_error_value_from_union(left, right);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else if (mpz_cmp_si(mpq_denref(right->mpq), 1) == 0)
|
|
{
|
|
if (mpq_sgn(right->mpq) > 0)
|
|
{
|
|
if (mpz_fits_ulong_p(mpq_numref(right->mpq)))
|
|
{
|
|
unsigned long r = mpz_get_ui(mpq_numref(right->mpq));
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_div_2exp(q, left->mpq, r);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot right bitshift beyond ULONG_MAX");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot right bitshift by a negative value");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot right bitshift by a fractional value");
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_leftbitshift:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
retval = new_error_value_from_union(left, right);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else if (mpz_cmp_si(mpq_denref(right->mpq), 1) == 0)
|
|
{
|
|
if (mpq_sgn(right->mpq) > 0)
|
|
{
|
|
if (mpz_fits_ulong_p(mpq_numref(right->mpq)))
|
|
{
|
|
unsigned long rshift = mpz_get_ui(mpq_numref(right->mpq));
|
|
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_mul_2exp(q, left->mpq, rshift);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot left bitshift beyond ULONG_MAX");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot left bitshift by a negative value");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot left bitshift by fractional value");
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_exponent:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
retval = new_error_value_from_union(left, right);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else if (mpz_cmp_si(mpq_denref(right->mpq), 1) == 0)
|
|
{
|
|
if (mpq_sgn(right->mpq) > 0)
|
|
{
|
|
if (mpz_fits_ulong_p(mpq_numref(right->mpq)))
|
|
{
|
|
unsigned long rpow = mpz_get_ui(mpq_numref(right->mpq));
|
|
|
|
mpz_t n, d;
|
|
|
|
mpz_init(n), mpz_init(d);
|
|
|
|
mpz_pow_ui(n, mpq_numref(left->mpq), rpow);
|
|
mpz_pow_ui(d, mpq_denref(left->mpq), rpow);
|
|
|
|
mpq_t q, t;
|
|
|
|
mpq_init(q), mpq_init(t);
|
|
|
|
mpq_set_z(q, n);
|
|
mpq_set_z(t, d);
|
|
|
|
mpq_div(q, q, t);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q), mpq_clear(t);
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot exponentiate beyond ULONG_MAX");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: negative exponents not supported");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval = new_error_value_from_fmt(
|
|
"error: cannot exponentiate by a fraction");
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_divide:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
#if 0
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
mpq_div(q, left->mpq, right->mpq);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
#endif
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_remainder:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
retval = inc_value(right);
|
|
}
|
|
else
|
|
{
|
|
mpq_t q;
|
|
|
|
mpq_init(q);
|
|
|
|
// (x % y) => x - (x // y) * y
|
|
|
|
mpq_div(q, left->mpq, right->mpq);
|
|
|
|
mpz_tdiv_q(mpq_numref(q), mpq_numref(q), mpq_denref(q));
|
|
|
|
mpz_set_si(mpq_denref(q), 1);
|
|
|
|
mpq_mul(q, q, right->mpq);
|
|
|
|
mpq_sub(q, left->mpq, q);
|
|
|
|
retval = new_value(q);
|
|
|
|
mpq_clear(q);
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_positive:
|
|
{
|
|
retval = evaluate(expression->center, scope);
|
|
break;
|
|
}
|
|
|
|
case ek_negative:
|
|
{
|
|
struct value* sub = evaluate(expression->center, scope);
|
|
|
|
if (sub->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
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:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
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);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case ek_greater_than_equal_to:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
case ek_less_than:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
|
|
if (left->kind == vk_error && right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else if (left->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else if (right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
}
|
|
else
|
|
{
|
|
retval = new_value_from_int(mpq_cmp(left->mpq, right->mpq) == 0);
|
|
}
|
|
|
|
free_value(left), free_value(right);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_not_equal_to:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
case ek_logical_not:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
struct value* sub = evaluate(expression->center, scope);
|
|
|
|
retval = new_value_from_int(mpq_sgn(sub->mpq) == 0);
|
|
|
|
free_value(sub);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
case ek_logical_and:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
case ek_logical_or:
|
|
{
|
|
struct value* left = evaluate(expression->left, scope);
|
|
|
|
if (left->kind == vk_error)
|
|
{
|
|
struct value* right = evaluate(expression->right, scope);
|
|
|
|
if (right->kind == vk_error)
|
|
{
|
|
TODO;
|
|
// new_error_value_from_union
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_update(set, left->errors);
|
|
stringset_update(set, right->errors);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
}
|
|
else
|
|
{
|
|
retval = inc_value(left);
|
|
}
|
|
|
|
free_value(right);
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
#if 0
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
free_value(left);
|
|
|
|
break;
|
|
}
|
|
|
|
case ek_ternary:
|
|
{
|
|
struct value* conditional = evaluate(expression->center, scope);
|
|
|
|
if (conditional->kind == vk_error)
|
|
{
|
|
retval = inc_value(conditional);
|
|
}
|
|
else if (mpq_sgn(conditional->mpq) != 0)
|
|
{
|
|
retval = evaluate(expression->left, scope);
|
|
}
|
|
else
|
|
{
|
|
retval = evaluate(expression->right, scope);
|
|
}
|
|
|
|
free_value(conditional);
|
|
break;
|
|
}
|
|
|
|
case ek_assign:
|
|
{
|
|
if (expression->left->kind == ek_variable)
|
|
{
|
|
struct value** lvalue = scope_lookup(
|
|
scope, expression->left->string);
|
|
|
|
retval = evaluate(expression->right, scope);
|
|
|
|
free_value(*lvalue), *lvalue = inc_value(retval);
|
|
}
|
|
else
|
|
{
|
|
TODO;
|
|
|
|
struct string* message = new_string_from_fmt(
|
|
"error: cannot assign to rvalue-expressions");
|
|
|
|
struct stringset* set = new_stringset();
|
|
|
|
stringset_add(set, message);
|
|
|
|
retval = new_error_value(set);
|
|
|
|
free_stringset(set);
|
|
|
|
free_string(message);
|
|
}
|
|
|
|
break;
|
|
};
|
|
|
|
case ek_comma:
|
|
{
|
|
TODO;
|
|
#if 0
|
|
free_value(evaluate(expression->left, scope));
|
|
|
|
retval = evaluate(expression->right, scope);
|
|
|
|
break;
|
|
#endif
|
|
};
|
|
}
|
|
|
|
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 = (unsigned int) 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)
|
|
{
|
|
switch (this->kind)
|
|
{
|
|
case vk_error:
|
|
{
|
|
stringset_println(this->errors);
|
|
|
|
break;
|
|
}
|
|
|
|
case vk_number:
|
|
{
|
|
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("");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void syntax_error_print(
|
|
const struct expression* this)
|
|
{
|
|
assert(this->kind == ek_syntax_error);
|
|
|
|
printf("%*s↑\n", this->column - 1, "");
|
|
printf("%*s└ %s\n", this->column - 1, "", this->string->data);
|
|
}
|
|
|
|
int main(int argc, char* const* argv)
|
|
{
|
|
int retval = 0;
|
|
|
|
parse_args(argc, argv);
|
|
|
|
if (command)
|
|
{
|
|
struct scope* scope = new_scope();
|
|
|
|
struct expression* expression = parse(command);
|
|
|
|
if (expression->kind == ek_syntax_error)
|
|
{
|
|
printf("syntax error!\n");
|
|
|
|
printf("%s\n", command);
|
|
|
|
syntax_error_print(expression);
|
|
|
|
retval = 1;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
|
|
TODO; // switch on value kind
|
|
// print(value);
|
|
|
|
free_value(value);
|
|
|
|
free_expression(expression);
|
|
}
|
|
|
|
free_scope(scope);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|