cake
/
libg1m
Archived
1
0
Fork 0
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libg1m/src/basic/instruction.c.draft

233 lines
6.2 KiB
Plaintext

/* ************************************************************************** */
/* _____ _ */
/* basic/instruction.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2017/01/07 14:55:53 |___/ */
/* */
/* ************************************************************************** */
#include <libg1m/internals.h>
#define go_forward(N) *buf += (N); *size -= (N)
/* ************************************************************************** */
/* Utilities */
/* ************************************************************************** */
/**
* parse_bcd:
* Parse a BCD.
*
* @arg buf the FONTCHARACTER buffer.
* @arg size the buffer size.
* @arg real the real part.
* @arg imgn the imaginary part.
* @return the error.
*/
static int fetch_bcd(const FONTCHARACTER **buf, size_t *size,
struct bcd *real, struct bcd *imgn)
{
/* TODO */
return (g1m_error_eof);
}
/**
* fetch_int:
* Decode an integer.
*
* @arg buf the FONTCHARACTER buffer.
* @arg size the buffer size.
* @arg num the integer to parse.
*/
static int fetch_int(const FONTCHARACTER **buf, size_t *size, int *id)
{
/* check the ans */
if (**buf == 0xC0) { *id = g1m_ans; (*buf)++; (*size)--; return (0); }
/* peek and get the size of the number */
int i; for (i = 0; i < *size && (*buf)[i] >= '0' && (*buf)[i] <= '9'; i++);
/* get the number */
int numsize = i;
*id = 0; while (i-- >= 0) *id = *id * 10 + (*buf)[i] - '0';
/* go forward and ok */
go_forward(numsize);
return (0);
}
/**
* fetch_argument:
* Decode an argument.
*
* @arg buf the FONTCHARACTER buffer.
* @arg size the buffer size.
* @arg arg the argument structure.
* @return if there was an error
*/
#define VAR(ID) (struct argument){.type = g1m_argtype_var, .id = (ID)}
static int fetch_argument(const FONTCHARACTER **buf, size_t *size,
struct argument *arg)
{
/* check if we have at least one character */
if (!*size) return (g1m_error_eof);
/* check if is something special */
FONTCHARACTER op = **buf;
if (opcode == 0xF93F) { arg->type = g1m_argtype_string; goto parse_id; }
if (opcode == 0x7F40) { arg->type = g1m_argtype_mat; goto parse_let; }
if (opcode == 0x7F51) { arg->type = g1m_argtype_list; goto parse_id; }
/* check if it's a var */
if (op == 0xC0) *arg = VAR(g1m_ans);
else if (op == 0xCE) *arg = VAR(g1m_theta);
else if (op == 0xCD) *arg = VAR(g1m_r);
else if (op >= 'A' && op <= 'Z') *arg = VAR(op - 'A');
else {
int err = fetch_bcd(buf, size, &arg->real, &arg->imgn);
if (err) return (fetch_statement(buf, size, arg->statement));
return (err);
}
/* was a var */
go_forward(1);
return (0);
/* it's something with an ID! */
parse_id:
go_forward(1);
return (fetch_int(buf, size, &arg->id));
/* it's something with a letter ID! */
parse_let:
go_forward(1);
return (fetch_let(buf, size, &arg->id));
}
/* ************************************************************************** */
/* Statements */
/* ************************************************************************** */
/* Statements */
struct statement {
/* the start opcode */
FONTCHARACTER opcode;
/* number of arguments */
int nargs;
/* finishes with a parenthesis */
int par;
};
/* Known statements */
static const struct statement statements[] = {
/* Locate x,x,x */
{0xF710, 3, 0},
/* Send(A) */
{0xF711, 1, 1},
/* Receive(A) */
{0xF712, 1, 1},
{0, 0}
};
/* Infix statements */
static const struct statement infix_statements[] = {
/* x! */
{0xEA, 1, 0},
/* a = b */
{0x3D, 2, 0},
{0, 0}
};
/**
* fetch_raw_statement:
* Fetch a statement.
*
* @arg buf the FONTCHARACTER buffer pointer.
* @arg size the FONTCHARACTER buffer size pointer.
* @arg st the statement pointer.
* @arg fst the first argument
* @arg infix is infix (boolean!)
* @return the error.
*/
static int fetch_raw_statement(const FONTCHARACTER **buf, size_t *size,
struct statement *st, struct argument *fst, int infix)
{
/* check if there is at least space for one opcode */
if (!*size) return (1);
/* get the statements tab */
const struct *sts =
(const *struct statement[]){statements, infix_statements}[infix];
/* check which opcode it is */
FONTCHARACTER op = **buf;
const struct *st;
for (st = sts; st->opcode && st->opcode != op; st++);
if (!st) return (1);
/* prepare the arguments */
int nargs = st->nargs;
struct argument *args = malloc(nargs * sizeof(struct argument));
if (!args) return (1);
if (nargs) memcpy(&args[0], fst, sizeof(struct argument));
/* iterate */
int last = infix - 1;
for (int i = infix; i < nargs; i++) {
/* parse the arg */
if (fetch_argument(buf, size, &args[i]))
return (1);
/* check the comma */
if (i < last && (!*size || **buf != ','))
return (1);
go_forward(1);
}
/* check right parenthesis */
if (st->par && *size && **buf != ')')
return (1);
if (*size) { go_forward(1); }
/* no error */
return (0);
}
/**
* fetch_statement:
* Fetch a statement.
*/
/* ************************************************************************** */
/* Main function */
/* ************************************************************************** */
/**
* g1m_fetch_instruction:
* Fetch the instruction.
*
* @arg buf the FONTCHARACTER buffer.
* @arg size the FONTCHARACTER buffer size.
* @arg statement the statement.
* @return if negative: the negative libg1m error code.
* otherwise: the size of the instruction.
*/
int g1m_fetch_instruction(const FONTCHARACTER *buf, size_t size,
g1m_bst_t *statement)
{
size_t sav = size;
/* start by free-ing statement content? */
/* TODO */
/* check it it's a statement */
int err = fetch_statement(&buf, &size, &statement, 0);
return (err ? -err : (int)(sav - size));
}