233 lines
6.2 KiB
Plaintext
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));
|
|
}
|