Skip to content

Commit

Permalink
libfpvm: don't use TOK_* inside fpvm.c
Browse files Browse the repository at this point in the history
Code generation will have no access to the token numbers assigned by the
parser, so we create our own numbering scheme and translate between
parsing and code generation.
  • Loading branch information
wpwrak authored and Sebastien Bourdeauducq committed Dec 12, 2011
1 parent 75e8acb commit b29910c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 40 deletions.
33 changes: 31 additions & 2 deletions software/libfpvm/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,36 @@

#define NDEBUG

#define IDENTIFIER_SIZE 24
enum ast_op {
op_trouble, /* null value */
op_ident,
op_constant,
op_plus,
op_minus,
op_multiply,
op_divide,
op_percent,
op_abs,
op_isin,
op_icos,
op_sin,
op_cos,
op_above,
op_below,
op_equal,
op_i2f,
op_f2i,
op_if,
op_tsign,
op_quake,
op_not,
op_sqr,
op_sqrt,
op_invsqrt,
op_min,
op_max,
op_int,
};

struct id {
int token;
Expand All @@ -36,7 +65,7 @@ struct ast_branches {
};

struct ast_node {
int token;
enum ast_op op;
/*
* label is an empty string:
* node is a constant
Expand Down
73 changes: 36 additions & 37 deletions software/libfpvm/fpvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include "ast.h"
#include "unique.h"
#include "parser_helper.h"
#include "parser.h"

const char *fpvm_version()
{
Expand Down Expand Up @@ -236,22 +235,22 @@ static int add_isn(struct fpvm_fragment *fragment, int opcode,
return 1;
}

static int operator2opcode(int token)
static int operator2opcode(enum ast_op op)
{
switch (token) {
case TOK_PLUS: return FPVM_OPCODE_FADD;
case TOK_MINUS: return FPVM_OPCODE_FSUB;
case TOK_MULTIPLY: return FPVM_OPCODE_FMUL;
case TOK_ABS: return FPVM_OPCODE_FABS;
case TOK_ISIN: return FPVM_OPCODE_SIN;
case TOK_ICOS: return FPVM_OPCODE_COS;
case TOK_ABOVE: return FPVM_OPCODE_ABOVE;
case TOK_EQUAL: return FPVM_OPCODE_EQUAL;
case TOK_I2F: return FPVM_OPCODE_I2F;
case TOK_F2I: return FPVM_OPCODE_F2I;
case TOK_IF: return FPVM_OPCODE_IF;
case TOK_TSIGN: return FPVM_OPCODE_TSIGN;
case TOK_QUAKE: return FPVM_OPCODE_QUAKE;
switch (op) {
case op_plus: return FPVM_OPCODE_FADD;
case op_minus: return FPVM_OPCODE_FSUB;
case op_multiply: return FPVM_OPCODE_FMUL;
case op_abs: return FPVM_OPCODE_FABS;
case op_isin: return FPVM_OPCODE_SIN;
case op_icos: return FPVM_OPCODE_COS;
case op_above: return FPVM_OPCODE_ABOVE;
case op_equal: return FPVM_OPCODE_EQUAL;
case op_i2f: return FPVM_OPCODE_I2F;
case op_f2i: return FPVM_OPCODE_F2I;
case op_if: return FPVM_OPCODE_IF;
case op_tsign: return FPVM_OPCODE_TSIGN;
case op_quake: return FPVM_OPCODE_QUAKE;
default:
return -1;
}
Expand Down Expand Up @@ -349,16 +348,16 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
int opa, opb;
int opcode;

switch(node->token) {
case TOK_CONSTANT:
switch(node->op) {
case op_constant:
/* AST node is a constant */
opa = REG_CONST(node->contents.constant);
if(reg != FPVM_INVALID_REG)
ADD_ISN(FPVM_OPCODE_COPY, opa, 0, reg);
else
reg = opa;
return reg;
case TOK_IDENT:
case op_ident:
/* AST node is a variable */
if(fragment->bind_mode) {
opa = sym_to_reg(fragment, node->label, 0, NULL);
Expand All @@ -378,7 +377,7 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
else
reg = opa;
return reg;
case TOK_IF:
case op_if:
/*
* "if" must receive a special treatment.
* It is implemented as a ternary function,
Expand All @@ -391,8 +390,8 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
opb = COMPILE(FPVM_INVALID_REG, node->contents.branches.c);
COMPILE(FPVM_REG_IFB, node->contents.branches.a);
break;
case TOK_NOT:
if(node->contents.branches.a->token == TOK_CONSTANT) {
case op_not:
if(node->contents.branches.a->op == op_constant) {
/* Node is a negative constant */
struct ast_node *n;

Expand All @@ -418,15 +417,15 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
if(reg == FPVM_INVALID_REG)
reg = fragment->next_sur--;

switch(node->token) {
case TOK_BELOW:
switch(node->op) {
case op_below:
/*
* "below" is like "above", but with reversed operands.
*/
ADD_ISN(FPVM_OPCODE_ABOVE, opb, opa, reg);
break;
case TOK_SIN:
case TOK_COS: {
case op_sin:
case op_cos: {
/*
* Trigo functions are implemented with several instructions.
* We must convert the floating point argument in radians
Expand All @@ -436,7 +435,7 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
int reg_mul = REG_ALLOC();
int reg_f2i = REG_ALLOC();

if(node->token == TOK_SIN)
if(node->op == op_sin)
opcode = FPVM_OPCODE_SIN;
else
opcode = FPVM_OPCODE_COS;
Expand All @@ -446,7 +445,7 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
ADD_ISN(opcode, reg_f2i, 0, reg);
break;
}
case TOK_SQRT: {
case op_sqrt: {
/*
* Square root is implemented with a variant of the Quake III
* algorithm.
Expand All @@ -459,10 +458,10 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
ADD_ISN(FPVM_OPCODE_FMUL, opa, reg_invsqrt, reg);
break;
}
case TOK_INVSQRT:
case op_invsqrt:
ADD_INV_SQRT(opa, reg);
break;
case TOK_DIVIDE: {
case op_divide: {
/*
* Floating point division is implemented as
* a/b = a*(1/sqrt(b))*(1/sqrt(b))
Expand All @@ -482,7 +481,7 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
ADD_ISN(FPVM_OPCODE_FMUL, reg_invsqrt2, reg_a2, reg);
break;
}
case TOK_PERCENT: {
case op_percent: {
int reg_invsqrt = REG_ALLOC();
int reg_invsqrt2 = REG_ALLOC();
int reg_div = REG_ALLOC();
Expand All @@ -498,29 +497,29 @@ static int compile(struct fpvm_fragment *fragment, int reg, struct ast_node *nod
ADD_ISN(FPVM_OPCODE_FSUB, opa, reg_bidiv, reg);
break;
}
case TOK_MIN:
case op_min:
ADD_ISN(FPVM_OPCODE_ABOVE, opa, opb, FPVM_REG_IFB);
ADD_ISN(FPVM_OPCODE_IF, opb, opa, reg);
break;
case TOK_MAX:
case op_max:
ADD_ISN(FPVM_OPCODE_ABOVE, opa, opb, FPVM_REG_IFB);
ADD_ISN(FPVM_OPCODE_IF, opa, opb, reg);
break;
case TOK_SQR:
case op_sqr:
ADD_ISN(FPVM_OPCODE_FMUL, opa, opa, reg);
break;
case TOK_INT:
case op_int:
ADD_INT(opa, reg);
break;
case TOK_NOT:
case op_not:
opb = find_negative_constant(fragment);
if(opb == FPVM_INVALID_REG)
return FPVM_INVALID_REG;
ADD_ISN(FPVM_OPCODE_TSIGN, opa, opb, reg);
break;
default:
/* Normal case */
opcode = operator2opcode(node->token);
opcode = operator2opcode(node->op);
if(opcode < 0) {
snprintf(fragment->last_error, FPVM_MAXERRLEN,
"Operation not supported: %s", node->label);
Expand Down
33 changes: 32 additions & 1 deletion software/libfpvm/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,44 @@
#include "parser.h"


const enum ast_op tok2op[] = {
[TOK_IDENT] = op_ident,
[TOK_CONSTANT] = op_constant,
[TOK_PLUS] = op_plus,
[TOK_MINUS] = op_minus,
[TOK_MULTIPLY] = op_multiply,
[TOK_DIVIDE] = op_divide,
[TOK_PERCENT] = op_percent,
[TOK_ABS] = op_abs,
[TOK_ISIN] = op_isin,
[TOK_ICOS] = op_icos,
[TOK_SIN] = op_sin,
[TOK_COS] = op_cos,
[TOK_ABOVE] = op_above,
[TOK_BELOW] = op_below,
[TOK_EQUAL] = op_equal,
[TOK_I2F] = op_i2f,
[TOK_F2I] = op_f2i,
[TOK_IF] = op_if,
[TOK_TSIGN] = op_tsign,
[TOK_QUAKE] = op_quake,
[TOK_NOT] = op_not,
[TOK_SQR] = op_sqr,
[TOK_SQRT] = op_sqrt,
[TOK_INVSQRT] = op_invsqrt,
[TOK_MIN] = op_min,
[TOK_MAX] = op_max,
[TOK_INT] = op_int,

};

struct ast_node *node(int token, const char *id, struct ast_node *a,
struct ast_node *b, struct ast_node *c)
{
struct ast_node *n;

n = malloc(sizeof(struct ast_node));
n->token = token;
n->op = tok2op[token];
n->label = id;
n->contents.branches.a = a;
n->contents.branches.b = b;
Expand Down

0 comments on commit b29910c

Please sign in to comment.