Clearer to understand the intent of node_t as a direct result of parsing source code.
195 lines
3.9 KiB
C
195 lines
3.9 KiB
C
/* parser.c
|
|
* Created: 2023-09-02
|
|
* Author: Aryadev Chavali
|
|
* Description: Functions for (de)serialising
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "./parser.h"
|
|
|
|
char *ast_to_str(ast_node_t *ast, size_t size)
|
|
{
|
|
char *out = calloc(size + 1, 1);
|
|
if (!out)
|
|
{
|
|
print_error(
|
|
"[internal]", 0, 0,
|
|
"ERROR: Out of Memory (could not allocate buffer in ast_to_str)");
|
|
return NULL;
|
|
}
|
|
for (size_t i = 0; i < size; ++i)
|
|
{
|
|
switch (ast[i].type)
|
|
{
|
|
case NEXT:
|
|
out[i] = '>';
|
|
break;
|
|
case PREV:
|
|
out[i] = '<';
|
|
break;
|
|
case INC:
|
|
out[i] = '+';
|
|
break;
|
|
case DEC:
|
|
out[i] = '-';
|
|
break;
|
|
case OUT:
|
|
out[i] = '.';
|
|
break;
|
|
case READ:
|
|
out[i] = ',';
|
|
break;
|
|
case LIN:
|
|
out[i] = '[';
|
|
break;
|
|
case LOUT:
|
|
out[i] = ']';
|
|
break;
|
|
}
|
|
}
|
|
out[size] = '\0';
|
|
return out;
|
|
}
|
|
|
|
struct PResult parse_buffer(buffer_t *buffer)
|
|
{
|
|
ast_node_t *nodes = NULL;
|
|
size_t usable = 0, loops = 0, loop_ends = 0;
|
|
|
|
// First pass: Compute |nodes|
|
|
for (size_t i = 0; i < buffer->size; ++i)
|
|
if (usable_character(buffer->data[i]))
|
|
{
|
|
++usable;
|
|
if (buffer->data[i] == '[')
|
|
++loops;
|
|
else if (buffer->data[i] == ']')
|
|
++loop_ends;
|
|
}
|
|
if (loops != loop_ends)
|
|
{
|
|
// Look for the point of failure
|
|
i64 stack = 0;
|
|
for (size_t i = 0, col = 0, row = 0; i < buffer->size; ++i)
|
|
{
|
|
if (buffer->data[i] == '\n')
|
|
{
|
|
col = 0;
|
|
++row;
|
|
continue;
|
|
}
|
|
else if (buffer->data[i] != ']' && buffer->data[i] != '[')
|
|
{
|
|
++col;
|
|
continue;
|
|
}
|
|
else if (buffer->data[i] == ']')
|
|
{
|
|
--stack;
|
|
}
|
|
else if (buffer->data[i] == '[')
|
|
{
|
|
++stack;
|
|
}
|
|
++col;
|
|
|
|
if (stack < 0)
|
|
{
|
|
print_error(buffer->name, row, col,
|
|
"ERROR: Unbalanced square brackets!");
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
nodes = calloc(usable, sizeof(*nodes));
|
|
if (!nodes)
|
|
{
|
|
print_error(
|
|
"[internal]", 0, 0,
|
|
"ERROR: Out of Memory (could not allocate buffer in parse_buffer)");
|
|
return (struct PResult){0};
|
|
}
|
|
|
|
// Second pass: parse nodes
|
|
for (size_t i = 0, col = 0, row = 1, nptr = 0; i < buffer->size; ++i)
|
|
{
|
|
++col;
|
|
if (buffer->data[i] == '\n')
|
|
{
|
|
++row;
|
|
col = 0;
|
|
}
|
|
else if (usable_character(buffer->data[i]))
|
|
{
|
|
nodes[nptr].col = col;
|
|
nodes[nptr].row = row;
|
|
switch (buffer->data[i])
|
|
{
|
|
case '>':
|
|
nodes[nptr].type = NEXT;
|
|
break;
|
|
case '<':
|
|
nodes[nptr].type = PREV;
|
|
break;
|
|
case '+':
|
|
nodes[nptr].type = INC;
|
|
break;
|
|
case '-':
|
|
nodes[nptr].type = DEC;
|
|
break;
|
|
case '.':
|
|
nodes[nptr].type = OUT;
|
|
break;
|
|
case ',':
|
|
nodes[nptr].type = READ;
|
|
break;
|
|
case '[':
|
|
nodes[nptr].type = LIN;
|
|
nodes[nptr].loop_ref = -1;
|
|
break;
|
|
case ']':
|
|
nodes[nptr].type = LOUT;
|
|
nodes[nptr].loop_ref = -1;
|
|
break;
|
|
}
|
|
++nptr;
|
|
}
|
|
}
|
|
|
|
// Third pass: setup loop references
|
|
size_t stackptr = 0;
|
|
if (loops)
|
|
{
|
|
ast_node_t *stack[loops];
|
|
memset(stack, 0, loops);
|
|
for (size_t i = 0; i < usable; ++i)
|
|
{
|
|
ast_node_t *node = nodes + i;
|
|
if (node->type == LIN)
|
|
stack[stackptr++] = node;
|
|
else if (node->type == LOUT)
|
|
{
|
|
// Access last IN loop
|
|
--stackptr;
|
|
node->loop_ref = stack[stackptr] - nodes;
|
|
stack[stackptr]->loop_ref = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stackptr > 0)
|
|
{
|
|
ast_node_t *node = nodes + usable - 1;
|
|
print_error(buffer->name, node->row, node->col,
|
|
"ERROR: Unbalanced square brackets!");
|
|
goto error;
|
|
}
|
|
|
|
return (struct PResult){nodes, usable, loops};
|
|
error:
|
|
if (nodes)
|
|
free(nodes);
|
|
return (struct PResult){0};
|
|
}
|