392 lines
12 KiB
C
392 lines
12 KiB
C
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
|
|
#include "hydroforth/hydroforth.h"
|
|
|
|
unsigned hydroforth__hash_string(const char *const key, unsigned char len)
|
|
{
|
|
unsigned char i = 0;
|
|
unsigned hash = 0;
|
|
while (i < len)
|
|
{
|
|
hash += key[i++];
|
|
hash += hash << 10;
|
|
hash ^= hash >> 6;
|
|
}
|
|
hash += hash << 3;
|
|
hash ^= hash >> 11;
|
|
hash += hash << 15;
|
|
|
|
return hash;
|
|
}
|
|
|
|
inline bool hydroforth__is_space(char c)
|
|
{
|
|
return c == ' ' || c == '\t';
|
|
}
|
|
|
|
HYDROFORTH__SCAN_NEXT_WORD_RESULT hydroforth__scan_next_word(HYDROFORTH__INTERPRETER *interpreter)
|
|
{
|
|
const unsigned long start = interpreter->pos;
|
|
unsigned char len = 0;
|
|
while (!hydroforth__is_space(interpreter->src[interpreter->pos]) && interpreter->src[interpreter->pos] != '\n' && interpreter->src[interpreter->pos])
|
|
{
|
|
len++;
|
|
interpreter->pos++;
|
|
}
|
|
|
|
return (HYDROFORTH__SCAN_NEXT_WORD_RESULT){
|
|
.start = start,
|
|
.len = len,
|
|
};
|
|
}
|
|
|
|
void hydroforth__add_word_to_word_definition(HYDROFORTH__WORD_DEFINITION *word_def, HYDROFORTH__WORD word)
|
|
{
|
|
word_def->words = realloc(word_def->words, sizeof(HYDROFORTH__WORD) * (word_def->words_len + 1));
|
|
word_def->words[word_def->words_len++] = word;
|
|
}
|
|
|
|
void hydroforth__parse(HYDROFORTH__RESULT *result, HYDROFORTH__INTERPRETER *interpreter, HYDROFORTH__WORD_DEFINITION *word_def)
|
|
{
|
|
const HYDROFORTH__SCAN_NEXT_WORD_RESULT res = hydroforth__scan_next_word(interpreter);
|
|
if (res.len == 1)
|
|
{
|
|
if (hydroforth__number__is_digit(interpreter->src[res.start]))
|
|
{
|
|
int n = interpreter->src[res.start] - '0';
|
|
if (word_def == NULL)
|
|
{
|
|
interpreter->call_stack[interpreter->call_stack_len++] = (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = n},
|
|
};
|
|
}
|
|
else
|
|
{
|
|
hydroforth__add_word_to_word_definition(word_def, (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = n},
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (interpreter->src[res.start])
|
|
{
|
|
case '\\':
|
|
do
|
|
{
|
|
interpreter->pos++;
|
|
} while (interpreter->src[interpreter->pos] != '\n' && interpreter->src[interpreter->pos]);
|
|
break;
|
|
|
|
case '(':
|
|
while (true)
|
|
{
|
|
interpreter->pos++;
|
|
if (interpreter->src[interpreter->pos] == ')' &&
|
|
(hydroforth__is_space(interpreter->src[interpreter->pos + 1]) ||
|
|
interpreter->src[interpreter->pos + 1] == '\n' ||
|
|
interpreter->src[interpreter->pos + 1] == '\0') ||
|
|
interpreter->src[interpreter->pos] == '\n' ||
|
|
interpreter->src[interpreter->pos] == '\0')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
case ':':
|
|
{
|
|
if (word_def != NULL)
|
|
{
|
|
hydroforth__set_func_result(result, ERR_WORD_DEF_INSIDE_WORD_DEF);
|
|
return;
|
|
}
|
|
|
|
printf("WORD DEFINITION\n");
|
|
do
|
|
{
|
|
interpreter->pos++;
|
|
} while (hydroforth__is_space(interpreter->src[interpreter->pos]) || interpreter->src[interpreter->pos] == '\n');
|
|
if (!interpreter->src[interpreter->pos])
|
|
{
|
|
hydroforth__set_func_result(result, ERR_UNTERMINATED_WORD_DEFINITION);
|
|
return;
|
|
}
|
|
if (hydroforth__number__is_digit(interpreter->src[interpreter->pos]))
|
|
{
|
|
hydroforth__set_func_result(result, ERR_WORD_NAME_CANT_BE_NUMBER);
|
|
return;
|
|
}
|
|
const HYDROFORTH__SCAN_NEXT_WORD_RESULT name_scan_res = hydroforth__scan_next_word(interpreter);
|
|
for (unsigned char i = 0; i < name_scan_res.len; i++)
|
|
{
|
|
putchar(interpreter->src[name_scan_res.start + i]);
|
|
}
|
|
putchar('\n');
|
|
|
|
if (name_scan_res.len == 1)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
unsigned hash = hydroforth__hash_string(interpreter->src + name_scan_res.start, name_scan_res.len);
|
|
printf("HASH: 0x%x\n", hash);
|
|
interpreter->word_definitions[interpreter->word_definitions_len] = (HYDROFORTH__WORD_DEFINITION){
|
|
.words = malloc(0),
|
|
.words_len = 0,
|
|
};
|
|
interpreter->word_keys[interpreter->word_keys_len++] = (HYDROFORTH__WORD_DEFINITION_WORD_KEY){
|
|
.hash = hash,
|
|
.key = {.word_definition_index = interpreter->word_definitions_len++},
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
if (word_def == NULL)
|
|
{
|
|
interpreter->call_stack[interpreter->call_stack_len++] = (HYDROFORTH__WORD){
|
|
.type = CHAR_WORD,
|
|
.data = {.char_word = interpreter->src[res.start]},
|
|
};
|
|
}
|
|
else
|
|
{
|
|
hydroforth__add_word_to_word_definition(word_def, (HYDROFORTH__WORD){
|
|
.type = CHAR_WORD,
|
|
.data = {.char_word = interpreter->src[res.start]},
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const bool next_is_digit = hydroforth__number__is_digit(interpreter->src[res.start + 1]);
|
|
if (next_is_digit && interpreter->src[res.start] == '-')
|
|
{
|
|
int n = hydroforth__number__parse_number(result, interpreter->src + res.start + 1, res.len - 1);
|
|
if (result->error)
|
|
{
|
|
hydroforth__add_func_backtrace(result);
|
|
return;
|
|
}
|
|
if (word_def == NULL)
|
|
{
|
|
interpreter->call_stack[interpreter->call_stack_len++] = (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = -n},
|
|
};
|
|
}
|
|
else
|
|
{
|
|
hydroforth__add_word_to_word_definition(word_def, (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = -n},
|
|
});
|
|
}
|
|
}
|
|
else if (next_is_digit && interpreter->src[res.start] == '+')
|
|
{
|
|
int n = hydroforth__number__parse_number(result, interpreter->src + res.start + 1, res.len - 1);
|
|
if (result->error)
|
|
{
|
|
hydroforth__add_func_backtrace(result);
|
|
return;
|
|
}
|
|
if (word_def == NULL)
|
|
{
|
|
interpreter->call_stack[interpreter->call_stack_len++] = (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = n},
|
|
};
|
|
}
|
|
else
|
|
{
|
|
hydroforth__add_word_to_word_definition(word_def, (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = n},
|
|
});
|
|
}
|
|
}
|
|
else if (hydroforth__number__is_digit(interpreter->src[res.start]))
|
|
{
|
|
int n = hydroforth__number__parse_number(result, interpreter->src + res.start, res.len);
|
|
if (result->error)
|
|
{
|
|
hydroforth__add_func_backtrace(result);
|
|
return;
|
|
}
|
|
if (word_def == NULL)
|
|
{
|
|
interpreter->call_stack[interpreter->call_stack_len++] = (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = n},
|
|
};
|
|
}
|
|
else
|
|
{
|
|
hydroforth__add_word_to_word_definition(word_def, (HYDROFORTH__WORD){
|
|
.type = PUSH,
|
|
.data = {.number = n},
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const unsigned hash = hydroforth__hash_string(interpreter->src + res.start, res.len);
|
|
switch (hash)
|
|
{
|
|
case 0x4078cde9: // --
|
|
do
|
|
{
|
|
interpreter->pos++;
|
|
} while (interpreter->src[interpreter->pos] != '\n' && interpreter->src[interpreter->pos]);
|
|
break;
|
|
|
|
default:
|
|
if (word_def == NULL)
|
|
{
|
|
interpreter->call_stack[interpreter->call_stack_len++] = (HYDROFORTH__WORD){
|
|
.type = WORD,
|
|
.data = {.hash = hash},
|
|
};
|
|
}
|
|
else
|
|
{
|
|
hydroforth__add_word_to_word_definition(word_def, (HYDROFORTH__WORD){
|
|
.type = WORD,
|
|
.data = {.hash = hash},
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void hydroforth__run_call_stack(HYDROFORTH__RESULT *result, HYDROFORTH__INTERPRETER *interpreter)
|
|
{
|
|
for (unsigned char i = interpreter->call_stack_len; i > 0; interpreter->call_stack_len--, i--)
|
|
{
|
|
const HYDROFORTH__WORD *word = interpreter->call_stack + i - 1;
|
|
switch (word->type)
|
|
{
|
|
case PUSH:
|
|
interpreter->stack[interpreter->stack_len++] = word->data.number;
|
|
break;
|
|
|
|
case CHAR_WORD:
|
|
switch (word->data.char_word)
|
|
{
|
|
case '-':
|
|
interpreter->stack[interpreter->stack_len - 2] -= interpreter->stack[interpreter->stack_len - 1];
|
|
interpreter->stack_len--;
|
|
break;
|
|
|
|
case '+':
|
|
interpreter->stack[interpreter->stack_len - 2] += interpreter->stack[interpreter->stack_len - 1];
|
|
interpreter->stack_len--;
|
|
break;
|
|
|
|
case '*':
|
|
interpreter->stack[interpreter->stack_len - 2] *= interpreter->stack[interpreter->stack_len - 1];
|
|
interpreter->stack_len--;
|
|
break;
|
|
|
|
case '/':
|
|
interpreter->stack[interpreter->stack_len - 2] /= interpreter->stack[interpreter->stack_len - 1];
|
|
interpreter->stack_len--;
|
|
break;
|
|
|
|
default:
|
|
hydroforth__set_func_result(result, ERR_UNKNOWN_SINGLE_CHAR_WORD);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case WORD:
|
|
printf("HASH: 0x%x\n", word->data.hash);
|
|
switch (word->data.hash)
|
|
{
|
|
case 0xaddd94c: // debug
|
|
const unsigned char left_width = hydroforth__number__count_digits(interpreter->stack_len);
|
|
unsigned char right_width = 0;
|
|
for (unsigned char i = 0; i < interpreter->stack_len; i++)
|
|
{
|
|
const unsigned char tmp = hydroforth__number__count_digits(interpreter->stack[i]);
|
|
if (tmp > right_width)
|
|
{
|
|
right_width = tmp;
|
|
}
|
|
}
|
|
for (unsigned char i = 0; i < (2 + left_width + 3 + right_width + 2); i++)
|
|
{
|
|
putchar('-');
|
|
}
|
|
putchar('\n');
|
|
for (unsigned char i = interpreter->stack_len - 1; i != 0xff; i--)
|
|
{
|
|
printf("| ");
|
|
const unsigned char left_index_width = left_width - hydroforth__number__count_digits(i);
|
|
for (unsigned char j = 0; j < left_index_width; j++)
|
|
{
|
|
putchar(' ');
|
|
}
|
|
printf("%u | ", i);
|
|
const unsigned char right_index_width = right_width - hydroforth__number__count_digits(interpreter->stack[i]);
|
|
for (unsigned char j = 0; j < right_index_width; j++)
|
|
{
|
|
putchar(' ');
|
|
}
|
|
printf("%i |\n", interpreter->stack[i]);
|
|
}
|
|
for (unsigned char i = 0; i < (2 + left_width + 3 + right_width + 2); i++)
|
|
{
|
|
putchar('-');
|
|
}
|
|
putchar('\n');
|
|
break;
|
|
|
|
default:
|
|
hydroforth__set_func_result(result, ERR_UNKNOWN_WORD);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void hydroforth__run(HYDROFORTH__RESULT *result, HYDROFORTH__INTERPRETER *interpreter)
|
|
{
|
|
while (true)
|
|
{
|
|
while (hydroforth__is_space(interpreter->src[interpreter->pos]) || interpreter->src[interpreter->pos] == '\n')
|
|
{
|
|
interpreter->pos++;
|
|
}
|
|
if (!interpreter->src[interpreter->pos])
|
|
{
|
|
return;
|
|
}
|
|
hydroforth__parse(result, interpreter, NULL);
|
|
if (result->error)
|
|
{
|
|
hydroforth__add_func_backtrace(result);
|
|
return;
|
|
}
|
|
hydroforth__run_call_stack(result, interpreter);
|
|
if (result->error)
|
|
{
|
|
hydroforth__add_func_backtrace(result);
|
|
return;
|
|
}
|
|
}
|
|
}
|