clang-format

This commit is contained in:
Neale Pickett 2024-12-04 18:40:53 -07:00
parent 9d3cce9bf6
commit ffc7d07214
6 changed files with 465 additions and 696 deletions

155
ctanks.c
View File

@ -1,11 +1,13 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "ctanks.h" #include "ctanks.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Debugging help */ /* Debugging help */
#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) #define DUMPf(fmt, args...) \
fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, \
##args)
#define DUMP() DUMPf("") #define DUMP() DUMPf("")
#define DUMP_d(v) DUMPf("%s = %d", #v, v) #define DUMP_d(v) DUMPf("%s = %d", #v, v)
#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v) #define DUMP_x(v) DUMPf("%s = 0x%x", #v, v)
@ -14,94 +16,63 @@
#define DUMP_f(v) DUMPf("%s = %f", #v, v) #define DUMP_f(v) DUMPf("%s = %f", #v, v)
#define DUMP_p(v) DUMPf("%s = %p", #v, v) #define DUMP_p(v) DUMPf("%s = %p", #v, v)
#define DUMP_xy(v) DUMPf("%s = (%f, %f)", #v, v[0], v[1]); #define DUMP_xy(v) DUMPf("%s = (%f, %f)", #v, v[0], v[1]);
#define DUMP_angle(v) DUMPf("%s = %.3fτ", #v, (v/TAU)); #define DUMP_angle(v) DUMPf("%s = %.3fτ", #v, (v / TAU));
#define sq(x) ((x) * (x)) #define sq(x) ((x) * (x))
void tank_init(struct tank *tank, tank_run_func *run, void *udata) {
void
tank_init(struct tank *tank, tank_run_func *run, void *udata)
{
memset(tank, 0, sizeof(*tank)); memset(tank, 0, sizeof(*tank));
tank->run = run; tank->run = run;
tank->udata = udata; tank->udata = udata;
} }
int int tank_fire_ready(struct tank *tank) { return (!tank->turret.recharge); }
tank_fire_ready(struct tank *tank)
{
return (! tank->turret.recharge);
}
void void tank_fire(struct tank *tank) {
tank_fire(struct tank *tank)
{
tank->turret.firing = tank_fire_ready(tank); tank->turret.firing = tank_fire_ready(tank);
} }
void void tank_set_speed(struct tank *tank, float left, float right) {
tank_set_speed(struct tank *tank, float left, float right)
{
tank->speed.desired[0] = min(max(left, -100), 100); tank->speed.desired[0] = min(max(left, -100), 100);
tank->speed.desired[1] = min(max(right, -100), 100); tank->speed.desired[1] = min(max(right, -100), 100);
} }
float float tank_get_turret(struct tank *tank) { return tank->turret.current; }
tank_get_turret(struct tank *tank)
{
return tank->turret.current;
}
void void tank_set_turret(struct tank *tank, float angle) {
tank_set_turret(struct tank *tank, float angle)
{
tank->turret.desired = fmodf(angle, TAU); tank->turret.desired = fmodf(angle, TAU);
} }
int int tank_get_sensor(struct tank *tank, int sensor_num) {
tank_get_sensor(struct tank *tank, int sensor_num)
{
if ((sensor_num < 0) || (sensor_num > TANK_MAX_SENSORS)) { if ((sensor_num < 0) || (sensor_num > TANK_MAX_SENSORS)) {
return 0; return 0;
} }
return tank->sensors[sensor_num].triggered; return tank->sensors[sensor_num].triggered;
} }
void void tank_set_led(struct tank *tank, int active) { tank->led = active; }
tank_set_led(struct tank *tank, int active)
{
tank->led = active;
}
static void static void rotate_point(float angle, float point[2]) {
rotate_point(float angle, float point[2])
{
float cos_, sin_; float cos_, sin_;
float new[2]; float new[2];
cos_ = cosf(angle); cos_ = cosf(angle);
sin_ = sinf(angle); sin_ = sinf(angle);
new[0] = point[0]*cos_ - point[1]*sin_; new[0] = point[0] * cos_ - point[1] * sin_;
new[1] = point[0]*sin_ + point[1]*cos_; new[1] = point[0] * sin_ + point[1] * cos_;
point[0] = new[0]; point[0] = new[0];
point[1] = new[1]; point[1] = new[1];
} }
static void tanks_fire_cannon(struct tanks_game *game, struct tank *this,
static void struct tank *that, float vector[2], float dist2) {
tanks_fire_cannon(struct tanks_game *game,
struct tank *this,
struct tank *that,
float vector[2],
float dist2)
{
float theta = this->angle + this->turret.current; float theta = this->angle + this->turret.current;
float rpos[2]; float rpos[2];
/* If someone's a crater, this is easy (unless we were just killed by the other one, in which case /* If someone's a crater, this is easy (unless we were just killed by the
we have to check the other direction) */ other one, in which case we have to check the other direction) */
if ((this->killer && this->killer != that) || that->killer) { if ((this->killer && this->killer != that) || that->killer) {
return; return;
} }
@ -118,7 +89,7 @@ tanks_fire_cannon(struct tanks_game *game,
} }
/* No need to check if it's not even firing */ /* No need to check if it's not even firing */
if (! this->turret.firing) { if (!this->turret.firing) {
return; return;
} }
@ -138,14 +109,9 @@ tanks_fire_cannon(struct tanks_game *game,
} }
} }
static void static void tanks_sensor_calc(struct tanks_game *game, struct tank *this,
tanks_sensor_calc(struct tanks_game *game, struct tank *that, float vector[2], float dist2) {
struct tank *this, int i;
struct tank *that,
float vector[2],
float dist2)
{
int i;
/* If someone's a crater, this is easy */ /* If someone's a crater, this is easy */
if (this->killer || that->killer) { if (this->killer || that->killer) {
@ -211,14 +177,9 @@ tanks_sensor_calc(struct tanks_game *game,
} }
} }
void void compute_vector(struct tanks_game *game, float vector[2], float *dist2,
compute_vector(struct tanks_game *game, struct tank *this, struct tank *that) {
float vector[2], int i;
float *dist2,
struct tank *this,
struct tank *that)
{
int i;
/* Establish shortest vector from center of this to center of that, /* Establish shortest vector from center of this to center of that,
* taking wrapping into account */ * taking wrapping into account */
@ -228,8 +189,7 @@ compute_vector(struct tanks_game *game,
vector[i] = that->position[i] - this->position[i]; vector[i] = that->position[i] - this->position[i];
if (vector[i] > halfsize) { if (vector[i] > halfsize) {
vector[i] = vector[i] - game->size[i]; vector[i] = vector[i] - game->size[i];
} } else if (vector[i] < -halfsize) {
else if (vector[i] < -halfsize) {
vector[i] = game->size[i] + vector[i]; vector[i] = game->size[i] + vector[i];
} }
} }
@ -238,18 +198,15 @@ compute_vector(struct tanks_game *game,
*dist2 = sq(vector[0]) + sq(vector[1]); *dist2 = sq(vector[0]) + sq(vector[1]);
} }
void void tanks_move_tank(struct tanks_game *game, struct tank *tank) {
tanks_move_tank(struct tanks_game *game, int i;
struct tank *tank)
{
int i;
float movement; float movement;
float angle; float angle;
int dir = 1; int dir = 1;
/* Rotate the turret */ /* Rotate the turret */
{ {
float rot_angle; /* Quickest way there */ float rot_angle; /* Quickest way there */
/* Constrain rot_angle to between -PI and PI */ /* Constrain rot_angle to between -PI and PI */
rot_angle = tank->turret.desired - tank->turret.current; rot_angle = tank->turret.desired - tank->turret.current;
@ -268,18 +225,18 @@ tanks_move_tank(struct tanks_game *game,
if (tank->speed.current[i] == tank->speed.desired[i]) { if (tank->speed.current[i] == tank->speed.desired[i]) {
/* Do nothing */ /* Do nothing */
} else if (tank->speed.current[i] < tank->speed.desired[i]) { } else if (tank->speed.current[i] < tank->speed.desired[i]) {
tank->speed.current[i] = min(tank->speed.current[i] + TANK_MAX_ACCEL, tank->speed.current[i] =
tank->speed.desired[i]); min(tank->speed.current[i] + TANK_MAX_ACCEL, tank->speed.desired[i]);
} else { } else {
tank->speed.current[i] = max(tank->speed.current[i] - TANK_MAX_ACCEL, tank->speed.current[i] =
tank->speed.desired[i]); max(tank->speed.current[i] - TANK_MAX_ACCEL, tank->speed.desired[i]);
} }
} }
/* The simple case */ /* The simple case */
if (tank->speed.current[0] == tank->speed.current[1]) { if (tank->speed.current[0] == tank->speed.current[1]) {
movement = tank->speed.current[0] * (TANK_TOP_SPEED / 100.0); movement = tank->speed.current[0] * (TANK_TOP_SPEED / 100.0);
angle = 0; angle = 0;
} else { } else {
/* pflarr's original comment: /* pflarr's original comment:
* *
@ -301,7 +258,8 @@ tanks_move_tank(struct tanks_game *game,
to be a penalty for having the treads go in opposite directions. to be a penalty for having the treads go in opposite directions.
This probably plays hell with precisely-planned tanks, which I This probably plays hell with precisely-planned tanks, which I
find very ha ha. */ find very ha ha. */
friction = TANK_FRICTION * (fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200); friction = TANK_FRICTION *
(fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200);
v[0] = tank->speed.current[0] * (1 - friction) * (TANK_TOP_SPEED / 100.0); v[0] = tank->speed.current[0] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
v[1] = tank->speed.current[1] * (1 - friction) * (TANK_TOP_SPEED / 100.0); v[1] = tank->speed.current[1] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
@ -330,7 +288,7 @@ tanks_move_tank(struct tanks_game *game,
theta = So/r theta = So/r
We multiply it by dir to adjust for the direction of rotation We multiply it by dir to adjust for the direction of rotation
*/ */
theta = So/r * dir; theta = So / r * dir;
movement = r * tanf(theta); movement = r * tanf(theta);
angle = theta; angle = theta;
@ -345,18 +303,16 @@ tanks_move_tank(struct tanks_game *game,
m[1] = sinf(tank->angle) * movement * dir; m[1] = sinf(tank->angle) * movement * dir;
for (i = 0; i < 2; i += 1) { for (i = 0; i < 2; i += 1) {
tank->position[i] = fmodf(tank->position[i] + m[i] + game->size[i], tank->position[i] =
game->size[i]); fmodf(tank->position[i] + m[i] + game->size[i], game->size[i]);
} }
} }
} }
void void tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks) {
tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks) int i, j;
{
int i, j;
float vector[2]; float vector[2];
float dist2; /* distance squared */ float dist2; /* distance squared */
/* It takes (at least) two to tank-o */ /* It takes (at least) two to tank-o */
if (ntanks < 2) { if (ntanks < 2) {
@ -369,7 +325,8 @@ tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks)
tanks[i].turret.firing = 0; tanks[i].turret.firing = 0;
tanks[i].turret.recharge = TANK_CANNON_RECHARGE; tanks[i].turret.recharge = TANK_CANNON_RECHARGE;
} }
if (tanks[i].killer) continue; if (tanks[i].killer)
continue;
if (tanks[i].turret.recharge) { if (tanks[i].turret.recharge) {
tanks[i].turret.recharge -= 1; tanks[i].turret.recharge -= 1;
} }
@ -380,13 +337,15 @@ tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks)
/* Move tanks */ /* Move tanks */
for (i = 0; i < ntanks; i += 1) { for (i = 0; i < ntanks; i += 1) {
if (tanks[i].killer) continue; if (tanks[i].killer)
continue;
tanks_move_tank(game, &(tanks[i])); tanks_move_tank(game, &(tanks[i]));
} }
/* Probe sensors */ /* Probe sensors */
for (i = 0; i < ntanks; i += 1) { for (i = 0; i < ntanks; i += 1) {
if (tanks[i].killer) continue; if (tanks[i].killer)
continue;
for (j = i + 1; j < ntanks; j += 1) { for (j = i + 1; j < ntanks; j += 1) {
struct tank *this = &tanks[i]; struct tank *this = &tanks[i];
struct tank *that = &tanks[j]; struct tank *that = &tanks[j];
@ -401,13 +360,15 @@ tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks)
/* Run programs */ /* Run programs */
for (i = 0; i < ntanks; i += 1) { for (i = 0; i < ntanks; i += 1) {
if (tanks[i].killer) continue; if (tanks[i].killer)
continue;
tanks[i].run(&tanks[i], tanks[i].udata); tanks[i].run(&tanks[i], tanks[i].udata);
} }
/* Fire cannons and check for crashes */ /* Fire cannons and check for crashes */
for (i = 0; i < ntanks; i += 1) { for (i = 0; i < ntanks; i += 1) {
if (tanks[i].killer) continue; if (tanks[i].killer)
continue;
for (j = i + 1; j < ntanks; j += 1) { for (j = i + 1; j < ntanks; j += 1) {
struct tank *this = &tanks[i]; struct tank *this = &tanks[i];
struct tank *that = &tanks[j]; struct tank *that = &tanks[j];

View File

@ -2,44 +2,44 @@
/* τ = 2π */ /* τ = 2π */
#define TAU 6.28318530717958647692 #define TAU 6.28318530717958647692
#define PI 3.14159265358979323846 #define PI 3.14159265358979323846
/* Some in-game constants */ /* Some in-game constants */
#define TANK_MAX_SENSORS 10 #define TANK_MAX_SENSORS 10
#define TANK_RADIUS 7.5 #define TANK_RADIUS 7.5
#define TANK_SENSOR_RANGE 100 #define TANK_SENSOR_RANGE 100
#define TANK_CANNON_RECHARGE 20 /* Turns to recharge cannon */ #define TANK_CANNON_RECHARGE 20 /* Turns to recharge cannon */
#define TANK_CANNON_RANGE (TANK_SENSOR_RANGE / 2) #define TANK_CANNON_RANGE (TANK_SENSOR_RANGE / 2)
#define TANK_MAX_ACCEL 35 #define TANK_MAX_ACCEL 35
#define TANK_MAX_TURRET_ROT (TAU/8) #define TANK_MAX_TURRET_ROT (TAU / 8)
#define TANK_TOP_SPEED 7 #define TANK_TOP_SPEED 7
#define TANK_FRICTION 0.75 #define TANK_FRICTION 0.75
/* (tank radius + tank radius)^2 */ /* (tank radius + tank radius)^2 */
#define TANK_COLLISION_ADJ2 \ #define TANK_COLLISION_ADJ2 \
((TANK_RADIUS + TANK_RADIUS) * (TANK_RADIUS + TANK_RADIUS)) ((TANK_RADIUS + TANK_RADIUS) * (TANK_RADIUS + TANK_RADIUS))
/* (Sensor range + tank radius)^2 /* (Sensor range + tank radius)^2
* If the distance^2 to the center of a tank <= TANK_SENSOR_ADJ2, * If the distance^2 to the center of a tank <= TANK_SENSOR_ADJ2,
* that tank is within sensor range. */ * that tank is within sensor range. */
#define TANK_SENSOR_ADJ2 \ #define TANK_SENSOR_ADJ2 \
((TANK_SENSOR_RANGE + TANK_RADIUS) * (TANK_SENSOR_RANGE + TANK_RADIUS)) ((TANK_SENSOR_RANGE + TANK_RADIUS) * (TANK_SENSOR_RANGE + TANK_RADIUS))
#define TANK_CANNON_ADJ2 \ #define TANK_CANNON_ADJ2 \
((TANK_CANNON_RANGE + TANK_RADIUS) * (TANK_CANNON_RANGE + TANK_RADIUS)) ((TANK_CANNON_RANGE + TANK_RADIUS) * (TANK_CANNON_RANGE + TANK_RADIUS))
#ifndef rad2deg #ifndef rad2deg
#define rad2deg(r) ((int)(360*(r)/TAU)) #define rad2deg(r) ((int)(360 * (r) / TAU))
#define deg2rad(r) ((r*TAU)/360) #define deg2rad(r) ((r * TAU) / 360)
#endif #endif
#ifndef max #ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b))
#endif #endif
struct tanks_game { struct tanks_game {
float size[2]; /* dimensions of playing field */ float size[2]; /* dimensions of playing field */
}; };
struct tank; struct tank;
@ -47,39 +47,38 @@ struct tank;
struct sensor { struct sensor {
float angle; float angle;
float width; float width;
int range; int range;
int turret; /* Mounted to turret? */ int turret; /* Mounted to turret? */
int triggered; int triggered;
}; };
typedef void tank_run_func(struct tank *, void *); typedef void tank_run_func(struct tank *, void *);
struct tank { struct tank {
float position[2]; /* Current position on the board */ float position[2]; /* Current position on the board */
float angle; /* Current orientation */ float angle; /* Current orientation */
struct { struct {
float current[2]; /* Current tread speed */ float current[2]; /* Current tread speed */
float desired[2]; /* Desired tread speed */ float desired[2]; /* Desired tread speed */
} speed; } speed;
struct { struct {
float current; /* Current turret angle */ float current; /* Current turret angle */
float desired; /* Desired turret angle */ float desired; /* Desired turret angle */
int firing; /* True if firing this turn */ int firing; /* True if firing this turn */
int recharge; /* Turns until gun is recharged */ int recharge; /* Turns until gun is recharged */
} turret; } turret;
struct sensor sensors[TANK_MAX_SENSORS]; /* Sensor array */ struct sensor sensors[TANK_MAX_SENSORS]; /* Sensor array */
int led; /* State of the LED */ int led; /* State of the LED */
struct tank *killer; /* Killer, or NULL if alive */ struct tank *killer; /* Killer, or NULL if alive */
char *cause_death; /* Cause of death */ char *cause_death; /* Cause of death */
tank_run_func *run; /* Function to run a tank */ tank_run_func *run; /* Function to run a tank */
void *udata; /* Argument to pass to run */ void *udata; /* Argument to pass to run */
}; };
void tank_init(struct tank *tank, tank_run_func *run, void *udata); void tank_init(struct tank *tank, tank_run_func *run, void *udata);
void tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks); void tanks_run_turn(struct tanks_game *game, struct tank *tanks, int ntanks);
/* /*
* *
* Tanks API for scripts * Tanks API for scripts

12
dump.h
View File

@ -7,7 +7,9 @@
#endif #endif
/* Debugging */ /* Debugging */
#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) #define DUMPf(fmt, args...) \
fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, \
##args)
#define DUMP() DUMPf("") #define DUMP() DUMPf("")
#define DUMP_d(v) DUMPf("%s = %d", #v, v) #define DUMP_d(v) DUMPf("%s = %d", #v, v)
#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v) #define DUMP_x(v) DUMPf("%s = 0x%x", #v, v)
@ -16,15 +18,17 @@
#define DUMP_f(v) DUMPf("%s = %f", #v, v) #define DUMP_f(v) DUMPf("%s = %f", #v, v)
#define DUMP_p(v) DUMPf("%s = %p", #v, v) #define DUMP_p(v) DUMPf("%s = %p", #v, v)
#define DUMP_xy(v) DUMPf("%s = (%f, %f)", #v, v[0], v[1]); #define DUMP_xy(v) DUMPf("%s = (%f, %f)", #v, v[0], v[1]);
#define DUMP_angle(v) DUMPf("%s = %.3fτ", #v, (v/TAU)); #define DUMP_angle(v) DUMPf("%s = %.3fτ", #v, (v / TAU));
/* Tektronix 4014 drawing */ /* Tektronix 4014 drawing */
#define TEK_ENABLE "\033[?38h" #define TEK_ENABLE "\033[?38h"
#define TEK_DISABLE "\033\003" #define TEK_DISABLE "\033\003"
#define TEK(fmt, args...) fprintf(stderr, TEK_ENABLE fmt TEK_DISABLE, ##args) #define TEK(fmt, args...) fprintf(stderr, TEK_ENABLE fmt TEK_DISABLE, ##args)
#define TEK_coord(x, y) ((int)y/32)+32,((int)y%32)+96,((int)x/32)+32,((int)x%32)+64 #define TEK_coord(x, y) \
((int)y / 32) + 32, ((int)y % 32) + 96, ((int)x / 32) + 32, ((int)x % 32) + 64
#define TEK_cls() TEK("\033\014") #define TEK_cls() TEK("\033\014")
#define TEK_line(x1, y1, x2, y2) TEK("\035%c%c%c%c%c%c%c%c", TEK_coord(x1, y1), TEK_coord(x2, y2)) #define TEK_line(x1, y1, x2, y2) \
TEK("\035%c%c%c%c%c%c%c%c", TEK_coord(x1, y1), TEK_coord(x2, y2))
#define TEK_point(x, y) TEK("\034%c%c%c%c", TEK_coord(x, y)) #define TEK_point(x, y) TEK("\034%c%c%c%c", TEK_coord(x, y))
#define TEK_text(x, y, s) TEK("\035%c%c%c%c\037%s", TEK_coord(x, y), s) #define TEK_text(x, y, s) TEK("\035%c%c%c%c\037%s", TEK_coord(x, y), s)

537
forf.c
View File

@ -27,28 +27,22 @@
* and not new stack types. * and not new stack types.
*/ */
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include "forf.h"
#include "dump.h" #include "dump.h"
#include "forf.h"
#ifndef max #ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b))
#endif #endif
char *forf_error_str[] = { char *forf_error_str[] = {
"None", "None", "Runtime", "Parse", "Underflow", "Overflow",
"Runtime", "Type", "No such procedure", "Divide by zero",
"Parse",
"Underflow",
"Overflow",
"Type",
"No such procedure",
"Divide by zero",
}; };
/* /*
@ -56,47 +50,29 @@ char *forf_error_str[] = {
* Memory manipulation * Memory manipulation
* *
*/ */
void void forf_memory_init(struct forf_memory *m, long *values, size_t size) {
forf_memory_init(struct forf_memory *m, m->mem = values;
long *values,
size_t size)
{
m->mem = values;
m->size = size; m->size = size;
} }
/* /*
* *
* Stack manipulation * Stack manipulation
* *
*/ */
void void forf_stack_init(struct forf_stack *s, struct forf_value *values,
forf_stack_init(struct forf_stack *s, size_t size) {
struct forf_value *values,
size_t size)
{
s->stack = values; s->stack = values;
s->size = size; s->size = size;
s->top = 0; s->top = 0;
} }
void void forf_stack_reset(struct forf_stack *s) { s->top = 0; }
forf_stack_reset(struct forf_stack *s)
{
s->top = 0;
}
size_t size_t forf_stack_len(struct forf_stack *s) { return s->top; }
forf_stack_len(struct forf_stack *s)
{
return s->top;
}
int int forf_stack_push(struct forf_stack *s, struct forf_value *v) {
forf_stack_push(struct forf_stack *s, struct forf_value *v)
{
if (s->top == s->size) { if (s->top == s->size) {
return 0; return 0;
} }
@ -104,9 +80,7 @@ forf_stack_push(struct forf_stack *s, struct forf_value *v)
return 1; return 1;
} }
int int forf_stack_pop(struct forf_stack *s, struct forf_value *v) {
forf_stack_pop(struct forf_stack *s, struct forf_value *v)
{
if (0 == s->top) { if (0 == s->top) {
return 0; return 0;
} }
@ -114,23 +88,18 @@ forf_stack_pop(struct forf_stack *s, struct forf_value *v)
return 1; return 1;
} }
void void forf_stack_copy(struct forf_stack *dst, struct forf_stack *src) {
forf_stack_copy(struct forf_stack *dst, struct forf_stack *src)
{
int top = min(dst->size, src->top); int top = min(dst->size, src->top);
dst->top = top; dst->top = top;
memcpy(dst->stack, src->stack, sizeof(*dst->stack) * top); memcpy(dst->stack, src->stack, sizeof(*dst->stack) * top);
} }
void forf_stack_reverse(struct forf_stack *s) {
void
forf_stack_reverse(struct forf_stack *s)
{
struct forf_value val; struct forf_value val;
size_t pos; size_t pos;
for (pos = 0; pos < (s->top)/2; pos += 1) { for (pos = 0; pos < (s->top) / 2; pos += 1) {
size_t qos = s->top - pos - 1; size_t qos = s->top - pos - 1;
val = s->stack[pos]; val = s->stack[pos];
@ -139,12 +108,10 @@ forf_stack_reverse(struct forf_stack *s)
} }
} }
long long forf_pop_num(struct forf_env *env) {
forf_pop_num(struct forf_env *env)
{
struct forf_value val; struct forf_value val;
if (! forf_stack_pop(env->data, &val)) { if (!forf_stack_pop(env->data, &val)) {
env->error = forf_error_underflow; env->error = forf_error_underflow;
return 0; return 0;
} }
@ -156,19 +123,16 @@ forf_pop_num(struct forf_env *env)
return val.v.i; return val.v.i;
} }
void void forf_push_num(struct forf_env *env, long i) {
forf_push_num(struct forf_env *env, long i)
{
struct forf_value val; struct forf_value val;
val.type = forf_type_number; val.type = forf_type_number;
val.v.i = i; val.v.i = i;
if (! forf_stack_push(env->data, &val)) { if (!forf_stack_push(env->data, &val)) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
} }
} }
/* Pop an entire stack /* Pop an entire stack
* *
* DANGER WILL ROBINSON * DANGER WILL ROBINSON
@ -177,14 +141,12 @@ forf_push_num(struct forf_env *env, long i)
* finished with this stack before you push anything onto the data * finished with this stack before you push anything onto the data
* stack, otherwise your returned stack will be corrupted. * stack, otherwise your returned stack will be corrupted.
*/ */
struct forf_stack struct forf_stack forf_pop_stack(struct forf_env *env) {
forf_pop_stack(struct forf_env *env) struct forf_stack s = {0, 0, NULL};
{
struct forf_stack s = { 0, 0, NULL };
struct forf_value val; struct forf_value val;
size_t depth = 1; size_t depth = 1;
if (! forf_stack_pop(env->data, &val)) { if (!forf_stack_pop(env->data, &val)) {
env->error = forf_error_underflow; env->error = forf_error_underflow;
return s; return s;
} }
@ -198,7 +160,7 @@ forf_pop_stack(struct forf_env *env)
s.size = -1; s.size = -1;
while (depth) { while (depth) {
s.size += 1; s.size += 1;
if (! forf_stack_pop(env->data, &val)) { if (!forf_stack_pop(env->data, &val)) {
/* You should never underflow here, there should at least be a /* You should never underflow here, there should at least be a
stack begin marker. */ stack begin marker. */
env->error = forf_error_runtime; env->error = forf_error_runtime;
@ -206,14 +168,14 @@ forf_pop_stack(struct forf_env *env)
return s; return s;
} }
switch (val.type) { switch (val.type) {
case forf_type_stack_end: case forf_type_stack_end:
depth += 1; depth += 1;
break; break;
case forf_type_stack_begin: case forf_type_stack_begin:
depth -= 1; depth -= 1;
break; break;
default: default:
break; break;
} }
} }
s.top = s.size; s.top = s.size;
@ -223,13 +185,11 @@ forf_pop_stack(struct forf_env *env)
/* Push an entire stack onto another stack. /* Push an entire stack onto another stack.
*/ */
int int forf_push_stack(struct forf_stack *dst, struct forf_stack *src) {
forf_push_stack(struct forf_stack *dst, struct forf_stack *src)
{
struct forf_value val; struct forf_value val;
while (forf_stack_pop(src, &val)) { while (forf_stack_pop(src, &val)) {
if (! forf_stack_push(dst, &val)) { if (!forf_stack_push(dst, &val)) {
return 0; return 0;
} }
} }
@ -240,10 +200,8 @@ forf_push_stack(struct forf_stack *dst, struct forf_stack *src)
* *
* This is meant to work with the return value from forf_pop_stack. * This is meant to work with the return value from forf_pop_stack.
*/ */
int int forf_push_to_command_stack(struct forf_env *env, struct forf_stack *src) {
forf_push_to_command_stack(struct forf_env *env, struct forf_stack *src) if (!forf_push_stack(env->command, src)) {
{
if (! forf_push_stack(env->command, src)) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
return 0; return 0;
} }
@ -259,24 +217,21 @@ forf_push_to_command_stack(struct forf_env *env, struct forf_stack *src)
* always have "reversed" substacks, and everything else will have them * always have "reversed" substacks, and everything else will have them
* in the right order. * in the right order.
*/ */
int int forf_stack_move_value(struct forf_env *env, struct forf_stack *dst,
forf_stack_move_value(struct forf_env *env, struct forf_stack *src) {
struct forf_stack *dst,
struct forf_stack *src)
{
struct forf_value val; struct forf_value val;
size_t depth = 0; size_t depth = 0;
do { do {
/* Pop from src */ /* Pop from src */
if (! forf_stack_pop(env->command, &val)) { if (!forf_stack_pop(env->command, &val)) {
env->error = forf_error_underflow; env->error = forf_error_underflow;
return 0; return 0;
} }
/* Push to dst (or discard if dst is NULL) */ /* Push to dst (or discard if dst is NULL) */
if (dst) { if (dst) {
if (! forf_stack_push(env->data, &val)) { if (!forf_stack_push(env->data, &val)) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
return 0; return 0;
} }
@ -284,68 +239,49 @@ forf_stack_move_value(struct forf_env *env,
/* Deal with it being a substack marker */ /* Deal with it being a substack marker */
switch (val.type) { switch (val.type) {
case forf_type_stack_begin: case forf_type_stack_begin:
depth += 1; depth += 1;
break; break;
case forf_type_stack_end: case forf_type_stack_end:
depth -= 1; depth -= 1;
break; break;
default: default:
break; break;
} }
} while (depth > 0); } while (depth > 0);
return 1; return 1;
} }
/* /*
* *
* Procedures * Procedures
* *
*/ */
#define unproc(name, op) \ #define unproc(name, op) \
static void \ static void forf_proc_##name(struct forf_env *env) { \
forf_proc_ ## name(struct forf_env *env) \ long a = forf_pop_num(env); \
{ \ \
long a = forf_pop_num(env); \ forf_push_num(env, op a); \
\
forf_push_num(env, op a); \
} }
unproc(inv, ~) unproc(inv, ~) unproc(not, !)
unproc(not, !)
#define binproc(name, op) \ #define binproc(name, op) \
static void \ static void forf_proc_##name(struct forf_env *env) { \
forf_proc_ ## name(struct forf_env *env) \ long a = forf_pop_num(env); \
{ \ long b = forf_pop_num(env); \
long a = forf_pop_num(env); \ \
long b = forf_pop_num(env); \ forf_push_num(env, b op a); \
\
forf_push_num(env, b op a); \
} }
binproc(add, +) binproc(add, +) binproc(sub, -) binproc(mul, *) binproc(and, &)
binproc(sub, -) binproc(or, |) binproc(xor, ^) binproc(lshift, <<) binproc(rshift, >>)
binproc(mul, *) binproc(gt, >) binproc(ge, >=) binproc(lt, <) binproc(le, <=)
binproc(and, &) binproc(eq, ==) binproc(ne, !=)
binproc(or, |)
binproc(xor, ^)
binproc(lshift, <<)
binproc(rshift, >>)
binproc(gt, >)
binproc(ge, >=)
binproc(lt, <)
binproc(le, <=)
binproc(eq, ==)
binproc(ne, !=)
static void static void forf_proc_div(struct forf_env *env) {
forf_proc_div(struct forf_env *env)
{
long a = forf_pop_num(env); long a = forf_pop_num(env);
long b = forf_pop_num(env); long b = forf_pop_num(env);
@ -356,9 +292,7 @@ forf_proc_div(struct forf_env *env)
forf_push_num(env, b / a); forf_push_num(env, b / a);
} }
static void static void forf_proc_mod(struct forf_env *env) {
forf_proc_mod(struct forf_env *env)
{
long a = forf_pop_num(env); long a = forf_pop_num(env);
long b = forf_pop_num(env); long b = forf_pop_num(env);
@ -369,30 +303,20 @@ forf_proc_mod(struct forf_env *env)
forf_push_num(env, b % a); forf_push_num(env, b % a);
} }
static void static void forf_proc_abs(struct forf_env *env) {
forf_proc_abs(struct forf_env *env)
{
forf_push_num(env, abs(forf_pop_num(env))); forf_push_num(env, abs(forf_pop_num(env)));
} }
static void static void forf_proc_dup(struct forf_env *env) {
forf_proc_dup(struct forf_env *env)
{
long a = forf_pop_num(env); long a = forf_pop_num(env);
forf_push_num(env, a); forf_push_num(env, a);
forf_push_num(env, a); forf_push_num(env, a);
} }
static void static void forf_proc_pop(struct forf_env *env) { forf_pop_num(env); }
forf_proc_pop(struct forf_env *env)
{
forf_pop_num(env);
}
static void static void forf_proc_exch(struct forf_env *env) {
forf_proc_exch(struct forf_env *env)
{
long a = forf_pop_num(env); long a = forf_pop_num(env);
long b = forf_pop_num(env); long b = forf_pop_num(env);
@ -400,23 +324,19 @@ forf_proc_exch(struct forf_env *env)
forf_push_num(env, b); forf_push_num(env, b);
} }
static void static void forf_proc_if(struct forf_env *env) {
forf_proc_if(struct forf_env *env) struct forf_stack ifclause = forf_pop_stack(env);
{ long cond = forf_pop_num(env);
struct forf_stack ifclause = forf_pop_stack(env);
long cond = forf_pop_num(env);
if (cond) { if (cond) {
forf_push_to_command_stack(env, &ifclause); forf_push_to_command_stack(env, &ifclause);
} }
} }
static void static void forf_proc_ifelse(struct forf_env *env) {
forf_proc_ifelse(struct forf_env *env)
{
struct forf_stack elseclause = forf_pop_stack(env); struct forf_stack elseclause = forf_pop_stack(env);
struct forf_stack ifclause = forf_pop_stack(env); struct forf_stack ifclause = forf_pop_stack(env);
long cond = forf_pop_num(env); long cond = forf_pop_num(env);
if (cond) { if (cond) {
forf_push_to_command_stack(env, &ifclause); forf_push_to_command_stack(env, &ifclause);
@ -425,11 +345,9 @@ forf_proc_ifelse(struct forf_env *env)
} }
} }
static void static void forf_proc_memset(struct forf_env *env) {
forf_proc_memset(struct forf_env *env)
{
long pos = forf_pop_num(env); long pos = forf_pop_num(env);
long a = forf_pop_num(env); long a = forf_pop_num(env);
if (pos >= env->memory->size) { if (pos >= env->memory->size) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
@ -439,9 +357,7 @@ forf_proc_memset(struct forf_env *env)
env->memory->mem[pos] = a; env->memory->mem[pos] = a;
} }
static void static void forf_proc_memget(struct forf_env *env) {
forf_proc_memget(struct forf_env *env)
{
long pos = forf_pop_num(env); long pos = forf_pop_num(env);
if (pos >= env->memory->size) { if (pos >= env->memory->size) {
@ -457,70 +373,63 @@ forf_proc_memget(struct forf_env *env)
* Lexical environment * Lexical environment
* *
*/ */
struct forf_lexical_env forf_base_lexical_env[] = { struct forf_lexical_env forf_base_lexical_env[] = {{"~", forf_proc_inv},
{"~", forf_proc_inv}, {"!", forf_proc_not},
{"!", forf_proc_not}, {"+", forf_proc_add},
{"+", forf_proc_add}, {"-", forf_proc_sub},
{"-", forf_proc_sub}, {"*", forf_proc_mul},
{"*", forf_proc_mul}, {"/", forf_proc_div},
{"/", forf_proc_div}, {"%", forf_proc_mod},
{"%", forf_proc_mod}, {"&", forf_proc_and},
{"&", forf_proc_and}, {"|", forf_proc_or},
{"|", forf_proc_or}, {"^", forf_proc_xor},
{"^", forf_proc_xor}, {"<<", forf_proc_lshift},
{"<<", forf_proc_lshift}, {">>", forf_proc_rshift},
{">>", forf_proc_rshift}, {">", forf_proc_gt},
{">", forf_proc_gt}, {">=", forf_proc_ge},
{">=", forf_proc_ge}, {"<", forf_proc_lt},
{"<", forf_proc_lt}, {"<=", forf_proc_le},
{"<=", forf_proc_le}, {"=", forf_proc_eq},
{"=", forf_proc_eq}, {"<>", forf_proc_ne},
{"<>", forf_proc_ne}, {"abs", forf_proc_abs},
{"abs", forf_proc_abs}, {"dup", forf_proc_dup},
{"dup", forf_proc_dup}, {"pop", forf_proc_pop},
{"pop", forf_proc_pop}, {"exch", forf_proc_exch},
{"exch", forf_proc_exch}, {"if", forf_proc_if},
{"if", forf_proc_if}, {"ifelse", forf_proc_ifelse},
{"ifelse", forf_proc_ifelse}, {"mset", forf_proc_memset},
{"mset", forf_proc_memset}, {"mget", forf_proc_memget},
{"mget", forf_proc_memget}, {NULL, NULL}};
{NULL, NULL}
};
/** Extend a lexical environment */ /** Extend a lexical environment */
int int forf_extend_lexical_env(struct forf_lexical_env *dest,
forf_extend_lexical_env(struct forf_lexical_env *dest, struct forf_lexical_env *src, size_t size) {
struct forf_lexical_env *src,
size_t size)
{
int base, i; int base, i;
for (base = 0; dest[base].name; base += 1); for (base = 0; dest[base].name; base += 1)
for (i = 0; (base+i < size) && (src[i].name); i += 1) { ;
dest[base+i] = src[i]; for (i = 0; (base + i < size) && (src[i].name); i += 1) {
dest[base + i] = src[i];
} }
if (base + i == size) { if (base + i == size) {
/* Not enough room */ /* Not enough room */
return 0; return 0;
} }
dest[base+i].name = NULL; dest[base + i].name = NULL;
dest[base+i].proc = NULL; dest[base + i].proc = NULL;
return 1; return 1;
} }
/* /*
* *
* Parsing * Parsing
* *
*/ */
static int static int forf_push_token(struct forf_env *env, char *token, size_t tokenlen) {
forf_push_token(struct forf_env *env, char *token, size_t tokenlen) long i;
{ char s[MAX_TOKEN_LEN + 1];
long i; char *endptr;
char s[MAX_TOKEN_LEN + 1]; struct forf_value val;
char *endptr;
struct forf_value val;
/* Zero-length token yields int:0 from strtol */ /* Zero-length token yields int:0 from strtol */
@ -549,7 +458,7 @@ forf_push_token(struct forf_env *env, char *token, size_t tokenlen)
} }
} }
if (! forf_stack_push(env->command, &val)) { if (!forf_stack_push(env->command, &val)) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
return 0; return 0;
} }
@ -558,25 +467,23 @@ forf_push_token(struct forf_env *env, char *token, size_t tokenlen)
} }
/* Parse an input stream onto the command stack */ /* Parse an input stream onto the command stack */
int int forf_parse_stream(struct forf_env *env, forf_getch_func *getch,
forf_parse_stream(struct forf_env *env, void *datum) {
forf_getch_func *getch, int running = 1;
void *datum) long pos = 0;
{ char token[MAX_TOKEN_LEN];
int running = 1; size_t tokenlen = 0;
long pos = 0;
char token[MAX_TOKEN_LEN];
size_t tokenlen = 0;
struct forf_value val; struct forf_value val;
size_t stack_depth = 0; size_t stack_depth = 0;
int comment = 0; int comment = 0;
#define _tokenize() \ #define _tokenize() \
do { \ do { \
if (tokenlen) { \ if (tokenlen) { \
if (! forf_push_token(env, token, tokenlen)) return pos; \ if (!forf_push_token(env, token, tokenlen)) \
tokenlen = 0; \ return pos; \
} \ tokenlen = 0; \
} \
} while (0) } while (0)
while (running) { while (running) {
@ -588,54 +495,54 @@ forf_parse_stream(struct forf_env *env,
/* Handle comments */ /* Handle comments */
if (comment) { if (comment) {
switch (c) { switch (c) {
case EOF: case EOF:
env->error = forf_error_parse; env->error = forf_error_parse;
return pos; return pos;
case ')': case ')':
comment = 0; comment = 0;
break; break;
} }
continue; continue;
} }
switch (c) { switch (c) {
case EOF: case EOF:
running = 0; running = 0;
break; break;
case '(': case '(':
comment = 1; comment = 1;
break; break;
case ' ': case ' ':
case '\f': case '\f':
case '\n': case '\n':
case '\r': case '\r':
case '\t': case '\t':
case '\v': case '\v':
_tokenize(); _tokenize();
break; break;
case '{': case '{':
_tokenize(); _tokenize();
val.type = forf_type_stack_begin; val.type = forf_type_stack_begin;
if (! forf_stack_push(env->command, &val)) { if (!forf_stack_push(env->command, &val)) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
return pos; return pos;
} }
stack_depth += 1; stack_depth += 1;
break; break;
case '}': case '}':
_tokenize(); _tokenize();
val.type = forf_type_stack_end; val.type = forf_type_stack_end;
if (! forf_stack_push(env->command, &val)) { if (!forf_stack_push(env->command, &val)) {
env->error = forf_error_overflow; env->error = forf_error_overflow;
return pos; return pos;
} }
stack_depth -= 1; stack_depth -= 1;
break; break;
default: default:
if (tokenlen < sizeof(token)) { if (tokenlen < sizeof(token)) {
token[tokenlen++] = c; token[tokenlen++] = c;
} }
break; break;
} }
} }
_tokenize(); _tokenize();
@ -652,25 +559,19 @@ forf_parse_stream(struct forf_env *env,
} }
struct forf_char_stream { struct forf_char_stream {
char *buf; char *buf;
size_t len; size_t len;
size_t pos; size_t pos;
}; };
static int static int forf_string_getch(struct forf_char_stream *stream) {
forf_string_getch(struct forf_char_stream *stream)
{
if (stream->pos >= stream->len) { if (stream->pos >= stream->len) {
return EOF; return EOF;
} }
return stream->buf[stream->pos++]; return stream->buf[stream->pos++];
} }
int int forf_parse_buffer(struct forf_env *env, char *buf, size_t len) {
forf_parse_buffer(struct forf_env *env,
char *buf,
size_t len)
{
struct forf_char_stream stream; struct forf_char_stream stream;
stream.buf = buf; stream.buf = buf;
@ -680,78 +581,62 @@ forf_parse_buffer(struct forf_env *env,
return forf_parse_stream(env, (forf_getch_func *)forf_string_getch, &stream); return forf_parse_stream(env, (forf_getch_func *)forf_string_getch, &stream);
} }
int int forf_parse_string(struct forf_env *env, char *str) {
forf_parse_string(struct forf_env *env,
char *str)
{
return forf_parse_buffer(env, str, strlen(str)); return forf_parse_buffer(env, str, strlen(str));
} }
int int forf_parse_file(struct forf_env *env, FILE *f) {
forf_parse_file(struct forf_env *env,
FILE *f)
{
return forf_parse_stream(env, (forf_getch_func *)fgetc, f); return forf_parse_stream(env, (forf_getch_func *)fgetc, f);
} }
/* /*
* *
* Forf environment * Forf environment
* *
*/ */
void void forf_env_init(struct forf_env *env, struct forf_lexical_env *lenv,
forf_env_init(struct forf_env *env, struct forf_stack *data, struct forf_stack *cmd,
struct forf_lexical_env *lenv, struct forf_memory *mem, void *udata) {
struct forf_stack *data, env->lenv = lenv;
struct forf_stack *cmd, env->data = data;
struct forf_memory *mem,
void *udata)
{
env->lenv = lenv;
env->data = data;
env->command = cmd; env->command = cmd;
env->memory = mem; env->memory = mem;
env->udata = udata; env->udata = udata;
} }
int forf_eval_once(struct forf_env *env) {
int
forf_eval_once(struct forf_env *env)
{
struct forf_value val; struct forf_value val;
if (! forf_stack_pop(env->command, &val)) { if (!forf_stack_pop(env->command, &val)) {
env->error = forf_error_underflow; env->error = forf_error_underflow;
return 0; return 0;
} }
switch (val.type) { switch (val.type) {
case forf_type_number: case forf_type_number:
case forf_type_stack_begin: case forf_type_stack_begin:
// Push back on command stack, then move it // Push back on command stack, then move it
forf_stack_push(env->command, &val); forf_stack_push(env->command, &val);
if (! forf_stack_move_value(env, env->data, env->command)) return 0; if (!forf_stack_move_value(env, env->data, env->command))
break;
case forf_type_proc:
(val.v.p)(env);
break;
default:
env->error = forf_error_runtime;
return 0; return 0;
break;
case forf_type_proc:
(val.v.p)(env);
break;
default:
env->error = forf_error_runtime;
return 0;
} }
return 1; return 1;
} }
int int forf_eval(struct forf_env *env) {
forf_eval(struct forf_env *env)
{
int ret; int ret;
env->error = forf_error_none; env->error = forf_error_none;
while (env->command->top) { while (env->command->top) {
ret = forf_eval_once(env); ret = forf_eval_once(env);
if ((! ret) || (env->error)) { if ((!ret) || (env->error)) {
return 0; return 0;
} }
} }

73
forf.h
View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h>
#define MAX_TOKEN_LEN 20 #define MAX_TOKEN_LEN 20
#define MAX_CMDSTACK 200 #define MAX_CMDSTACK 200
@ -28,42 +28,41 @@ enum forf_error_type {
extern char *forf_error_str[]; extern char *forf_error_str[];
typedef void (forf_proc)(struct forf_env *); typedef void(forf_proc)(struct forf_env *);
struct forf_value { struct forf_value {
enum forf_value_type type; enum forf_value_type type;
union { union {
forf_proc *p; forf_proc *p;
long i; long i;
} v; } v;
}; };
struct forf_stack { struct forf_stack {
size_t size; size_t size;
size_t top; size_t top;
struct forf_value *stack; struct forf_value *stack;
}; };
struct forf_memory { struct forf_memory {
size_t size; size_t size;
long *mem; long *mem;
}; };
struct forf_lexical_env { struct forf_lexical_env {
char *name; char *name;
forf_proc *proc; forf_proc *proc;
}; };
struct forf_env { struct forf_env {
enum forf_error_type error; enum forf_error_type error;
struct forf_lexical_env *lenv; struct forf_lexical_env *lenv;
struct forf_stack *data; struct forf_stack *data;
struct forf_stack *command; struct forf_stack *command;
struct forf_memory *memory; struct forf_memory *memory;
void *udata; void *udata;
}; };
/* /*
* *
* Main entry points * Main entry points
@ -71,14 +70,11 @@ struct forf_env {
*/ */
/** Initialize a memory structure, given an array of longs */ /** Initialize a memory structure, given an array of longs */
void forf_memory_init(struct forf_memory *m, void forf_memory_init(struct forf_memory *m, long *values, size_t size);
long *values,
size_t size);
/** Initialize a stack, given an array of values */ /** Initialize a stack, given an array of values */
void forf_stack_init(struct forf_stack *s, void forf_stack_init(struct forf_stack *s, struct forf_value *values,
struct forf_value *values, size_t size);
size_t size);
void forf_stack_reset(struct forf_stack *s); void forf_stack_reset(struct forf_stack *s);
void forf_stack_copy(struct forf_stack *dst, struct forf_stack *src); void forf_stack_copy(struct forf_stack *dst, struct forf_stack *src);
@ -94,51 +90,40 @@ void forf_push_num(struct forf_env *env, long i);
/** Pop a whole stack */ /** Pop a whole stack */
struct forf_stack forf_pop_stack(struct forf_env *env); struct forf_stack forf_pop_stack(struct forf_env *env);
/** The base lexical environment */ /** The base lexical environment */
extern struct forf_lexical_env forf_base_lexical_env[]; extern struct forf_lexical_env forf_base_lexical_env[];
/** Extend a lexical environment */ /** Extend a lexical environment */
int int forf_extend_lexical_env(struct forf_lexical_env *dest,
forf_extend_lexical_env(struct forf_lexical_env *dest, struct forf_lexical_env *src, size_t size);
struct forf_lexical_env *src,
size_t size);
/** Initialize a forf runtime environment. /** Initialize a forf runtime environment.
* *
* data, cmd, and mem should have already been initialized * data, cmd, and mem should have already been initialized
*/ */
void forf_env_init(struct forf_env *env, void forf_env_init(struct forf_env *env, struct forf_lexical_env *lenv,
struct forf_lexical_env *lenv, struct forf_stack *data, struct forf_stack *cmd,
struct forf_stack *data, struct forf_memory *mem, void *udata);
struct forf_stack *cmd,
struct forf_memory *mem,
void *udata);
/** The type of a getch function (used for parsing) */ /** The type of a getch function (used for parsing) */
typedef int (forf_getch_func)(void *); typedef int(forf_getch_func)(void *);
/** Parse something by calling getch(datum) /** Parse something by calling getch(datum)
* *
* Returns the character at which an error was encountered, or * Returns the character at which an error was encountered, or
* 0 for successful parse. * 0 for successful parse.
*/ */
int forf_parse_stream(struct forf_env *env, int forf_parse_stream(struct forf_env *env, forf_getch_func *getch,
forf_getch_func *getch, void *datum);
void *datum);
/** Parse a buffer */ /** Parse a buffer */
int forf_parse_buffer(struct forf_env *env, int forf_parse_buffer(struct forf_env *env, char *buf, size_t len);
char *buf,
size_t len);
/** Parse a string */ /** Parse a string */
int forf_parse_string(struct forf_env *env, int forf_parse_string(struct forf_env *env, char *str);
char *str);
/** Parse a FILE * */ /** Parse a FILE * */
int forf_parse_file(struct forf_env *env, int forf_parse_file(struct forf_env *env, FILE *f);
FILE *f);
/** Evaluate the topmost value on the command stack */ /** Evaluate the topmost value on the command stack */
int forf_eval_once(struct forf_env *env); int forf_eval_once(struct forf_env *env);

View File

@ -1,13 +1,13 @@
#include <sys/types.h> #include "ctanks.h"
#include <sys/stat.h> #include "dump.h"
#include <unistd.h> #include "forf.h"
#include <string.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <string.h>
#include "ctanks.h" #include <sys/stat.h>
#include "forf.h" #include <sys/types.h>
#include "dump.h" #include <unistd.h>
#define MAX_TANKS 50 #define MAX_TANKS 50
#define ROUNDS 500 #define ROUNDS 500
@ -20,28 +20,25 @@
#define MEMORY_SIZE 10 #define MEMORY_SIZE 10
struct forftank { struct forftank {
struct forf_env env; struct forf_env env;
int error_pos; int error_pos;
char color[8]; /* "#ff0088" */ char color[8]; /* "#ff0088" */
char name[50]; char name[50];
char *path; char *path;
unsigned int uid; unsigned int uid;
struct forf_stack _prog; struct forf_stack _prog;
struct forf_value _progvals[CSTACK_SIZE]; struct forf_value _progvals[CSTACK_SIZE];
struct forf_stack _cmd; struct forf_stack _cmd;
struct forf_value _cmdvals[CSTACK_SIZE]; struct forf_value _cmdvals[CSTACK_SIZE];
struct forf_stack _data; struct forf_stack _data;
struct forf_value _datavals[DSTACK_SIZE]; struct forf_value _datavals[DSTACK_SIZE];
struct forf_memory _mem; struct forf_memory _mem;
long _memvals[MEMORY_SIZE]; long _memvals[MEMORY_SIZE];
}; };
#ifndef NODEBUG #ifndef NODEBUG
void void forf_print_val(struct forf_value *val) {
forf_print_val(struct forf_value *val)
{
switch (val->type) { switch (val->type) {
case forf_type_number: case forf_type_number:
printf("%ld", val->v.i); printf("%ld", val->v.i);
@ -58,9 +55,7 @@ forf_print_val(struct forf_value *val)
} }
} }
void void forf_print_stack(struct forf_stack *s) {
forf_print_stack(struct forf_stack *s)
{
size_t pos; size_t pos;
for (pos = 0; pos < s->top; pos += 1) { for (pos = 0; pos < s->top; pos += 1) {
@ -69,9 +64,7 @@ forf_print_stack(struct forf_stack *s)
} }
} }
void void forf_dump_stack(struct forf_stack *s) {
forf_dump_stack(struct forf_stack *s)
{
printf("Stack at %p: ", s); printf("Stack at %p: ", s);
forf_print_stack(s); forf_print_stack(s);
printf("\n"); printf("\n");
@ -85,80 +78,64 @@ forf_dump_stack(struct forf_stack *s)
*/ */
/** Has the turret recharged? */ /** Has the turret recharged? */
void void forf_tank_fire_ready(struct forf_env *env) {
forf_tank_fire_ready(struct forf_env *env)
{
struct tank *tank = (struct tank *)env->udata; struct tank *tank = (struct tank *)env->udata;
forf_push_num(env, tank_fire_ready(tank)); forf_push_num(env, tank_fire_ready(tank));
} }
/** Fire! */ /** Fire! */
void void forf_tank_fire(struct forf_env *env) {
forf_tank_fire(struct forf_env *env)
{
struct tank *tank = (struct tank *)env->udata; struct tank *tank = (struct tank *)env->udata;
tank_fire(tank); tank_fire(tank);
} }
/** Set desired speed */ /** Set desired speed */
void void forf_tank_set_speed(struct forf_env *env) {
forf_tank_set_speed(struct forf_env *env) struct tank *tank = (struct tank *)env->udata;
{ long right = forf_pop_num(env);
struct tank *tank = (struct tank *)env->udata; long left = forf_pop_num(env);
long right = forf_pop_num(env);
long left = forf_pop_num(env);
tank_set_speed(tank, left, right); tank_set_speed(tank, left, right);
} }
/** Get the current turret angle */ /** Get the current turret angle */
void void forf_tank_get_turret(struct forf_env *env) {
forf_tank_get_turret(struct forf_env *env) struct tank *tank = (struct tank *)env->udata;
{ float angle = tank_get_turret(tank);
struct tank *tank = (struct tank *)env->udata;
float angle = tank_get_turret(tank);
forf_push_num(env, rad2deg(angle)); forf_push_num(env, rad2deg(angle));
} }
/** Set the desired turret angle */ /** Set the desired turret angle */
void void forf_tank_set_turret(struct forf_env *env) {
forf_tank_set_turret(struct forf_env *env) struct tank *tank = (struct tank *)env->udata;
{ long angle = forf_pop_num(env);
struct tank *tank = (struct tank *)env->udata;
long angle = forf_pop_num(env);
tank_set_turret(tank, deg2rad(angle)); tank_set_turret(tank, deg2rad(angle));
} }
/** Is a sensor active? */ /** Is a sensor active? */
void void forf_tank_get_sensor(struct forf_env *env) {
forf_tank_get_sensor(struct forf_env *env) struct tank *tank = (struct tank *)env->udata;
{ long sensor_num = forf_pop_num(env);
struct tank *tank = (struct tank *)env->udata;
long sensor_num = forf_pop_num(env);
forf_push_num(env, tank_get_sensor(tank, sensor_num)); forf_push_num(env, tank_get_sensor(tank, sensor_num));
} }
/** Set the LED state */ /** Set the LED state */
void void forf_tank_set_led(struct forf_env *env) {
forf_tank_set_led(struct forf_env *env) struct tank *tank = (struct tank *)env->udata;
{ long active = forf_pop_num(env);
struct tank *tank = (struct tank *)env->udata;
long active = forf_pop_num(env);
tank_set_led(tank, active); tank_set_led(tank, active);
} }
/** Pick a random number */ /** Pick a random number */
void void forf_proc_random(struct forf_env *env) {
forf_proc_random(struct forf_env *env)
{
long max = forf_pop_num(env); long max = forf_pop_num(env);
if (max < 1) { if (max < 1) {
forf_push_num(env, 0); forf_push_num(env, 0);
return; return;
@ -169,16 +146,15 @@ forf_proc_random(struct forf_env *env)
/* Tanks lexical environment */ /* Tanks lexical environment */
struct forf_lexical_env tanks_lenv_addons[] = { struct forf_lexical_env tanks_lenv_addons[] = {
{"fire-ready?", forf_tank_fire_ready}, {"fire-ready?", forf_tank_fire_ready},
{"fire!", forf_tank_fire}, {"fire!", forf_tank_fire},
{"set-speed!", forf_tank_set_speed}, {"set-speed!", forf_tank_set_speed},
{"get-turret", forf_tank_get_turret}, {"get-turret", forf_tank_get_turret},
{"set-turret!", forf_tank_set_turret}, {"set-turret!", forf_tank_set_turret},
{"sensor?", forf_tank_get_sensor}, {"sensor?", forf_tank_get_sensor},
{"set-led!", forf_tank_set_led}, {"set-led!", forf_tank_set_led},
{"random", forf_proc_random}, {"random", forf_proc_random},
{NULL, NULL} {NULL, NULL}};
};
/* /*
* *
@ -186,68 +162,61 @@ struct forf_lexical_env tanks_lenv_addons[] = {
* *
*/ */
int int ft_read_file(char *ptr, size_t size, char *dir, char *fn) {
ft_read_file(char *ptr, size_t size, char *dir, char *fn) char path[256];
{ FILE *f = NULL;
char path[256]; int ret;
FILE *f = NULL; int success = 0;
int ret;
int success = 0;
do { do {
snprintf(path, sizeof(path), "%s/%s", dir, fn); snprintf(path, sizeof(path), "%s/%s", dir, fn);
f = fopen(path, "r"); f = fopen(path, "r");
if (! f) break; if (!f)
break;
ret = fread(ptr, 1, size - 1, f); ret = fread(ptr, 1, size - 1, f);
ptr[ret] = '\0'; ptr[ret] = '\0';
if (! ret) break; if (!ret)
break;
success = 1; success = 1;
} while (0); } while (0);
if (f) fclose(f); if (f)
if (! success) { fclose(f);
if (!success) {
return 0; return 0;
} }
return 1; return 1;
} }
void void ft_bricked_tank(struct tank *tank, void *ignored) {
ft_bricked_tank(struct tank *tank, void *ignored)
{
/* Do nothing, the tank is comatose */ /* Do nothing, the tank is comatose */
} }
void void ft_run_tank(struct tank *tank, struct forftank *ftank) {
ft_run_tank(struct tank *tank, struct forftank *ftank)
{
int ret; int ret;
/* Copy program into command stack */ /* Copy program into command stack */
forf_stack_copy(&ftank->_cmd, &ftank->_prog); forf_stack_copy(&ftank->_cmd, &ftank->_prog);
forf_stack_reset(&ftank->_data); forf_stack_reset(&ftank->_data);
ret = forf_eval(&ftank->env); ret = forf_eval(&ftank->env);
if (! ret) { if (!ret) {
fprintf(stderr, "Error in %s: %s\n", fprintf(stderr, "Error in %s: %s\n", ftank->path,
ftank->path,
forf_error_str[ftank->env.error]); forf_error_str[ftank->env.error]);
} }
} }
int int ft_read_program(struct forftank *ftank, struct tank *tank,
ft_read_program(struct forftank *ftank, struct forf_lexical_env *lenv, char *path) {
struct tank *tank, char progpath[256];
struct forf_lexical_env *lenv,
char *path)
{
char progpath[256];
FILE *f; FILE *f;
/* Open program */ /* Open program */
snprintf(progpath, sizeof(progpath), "%s/program", path); snprintf(progpath, sizeof(progpath), "%s/program", path);
f = fopen(progpath, "r"); f = fopen(progpath, "r");
if (! f) return 0; if (!f)
return 0;
/* Parse program */ /* Parse program */
ftank->error_pos = forf_parse_file(&ftank->env, f); ftank->error_pos = forf_parse_file(&ftank->env, f);
@ -265,43 +234,33 @@ ft_read_program(struct forftank *ftank,
return 1; return 1;
} }
void void ft_tank_init(struct forftank *ftank, struct tank *tank,
ft_tank_init(struct forftank *ftank, struct forf_lexical_env *lenv) {
struct tank *tank,
struct forf_lexical_env *lenv)
{
/* Set up forf environment */ /* Set up forf environment */
forf_stack_init(&ftank->_prog, ftank->_progvals, CSTACK_SIZE); forf_stack_init(&ftank->_prog, ftank->_progvals, CSTACK_SIZE);
forf_stack_init(&ftank->_cmd, ftank->_cmdvals, CSTACK_SIZE); forf_stack_init(&ftank->_cmd, ftank->_cmdvals, CSTACK_SIZE);
forf_stack_init(&ftank->_data, ftank->_datavals, DSTACK_SIZE); forf_stack_init(&ftank->_data, ftank->_datavals, DSTACK_SIZE);
forf_memory_init(&ftank->_mem, ftank->_memvals, MEMORY_SIZE); forf_memory_init(&ftank->_mem, ftank->_memvals, MEMORY_SIZE);
forf_env_init(&ftank->env, forf_env_init(&ftank->env, lenv, &ftank->_data, &ftank->_cmd, &ftank->_mem,
lenv,
&ftank->_data,
&ftank->_cmd,
&ftank->_mem,
tank); tank);
} }
void void ft_read_sensors(struct tank *tank, char *path) {
ft_read_sensors(struct tank *tank,
char *path)
{
int i; int i;
for (i = 0; i < TANK_MAX_SENSORS; i += 1) { for (i = 0; i < TANK_MAX_SENSORS; i += 1) {
int ret; int ret;
char fn[10]; char fn[10];
char s[20]; char s[20];
char *p = s; char *p = s;
long range; long range;
long angle; long angle;
long width; long width;
long turret; long turret;
snprintf(fn, sizeof(fn), "sensor%d", i); snprintf(fn, sizeof(fn), "sensor%d", i);
ret = ft_read_file(s, sizeof(s), path, fn); ret = ft_read_file(s, sizeof(s), path, fn);
if (! ret) { if (!ret) {
s[0] = 0; s[0] = 0;
} }
range = strtol(p, &p, 0); range = strtol(p, &p, 0);
@ -316,12 +275,8 @@ ft_read_sensors(struct tank *tank,
} }
} }
int int ft_read_tank(struct forftank *ftank, struct tank *tank,
ft_read_tank(struct forftank *ftank, struct forf_lexical_env *lenv, char *path) {
struct tank *tank,
struct forf_lexical_env *lenv,
char *path)
{
int ret; int ret;
ftank->path = path; ftank->path = path;
@ -338,7 +293,7 @@ ft_read_tank(struct forftank *ftank,
/* What is your name? */ /* What is your name? */
ret = ft_read_file(ftank->name, sizeof(ftank->name), path, "name"); ret = ft_read_file(ftank->name, sizeof(ftank->name), path, "name");
if (! ret) { if (!ret) {
snprintf(ftank->name, sizeof(ftank->name), "i:%x", ftank->uid); snprintf(ftank->name, sizeof(ftank->name), "i:%x", ftank->uid);
} }
@ -354,29 +309,21 @@ ft_read_tank(struct forftank *ftank,
/* What is your favorite color? */ /* What is your favorite color? */
ret = ft_read_file(ftank->color, sizeof(ftank->color), path, "color"); ret = ft_read_file(ftank->color, sizeof(ftank->color), path, "color");
if (! ret) { if (!ret) {
strncpy(ftank->color, "#808080", sizeof(ftank->color)); strncpy(ftank->color, "#808080", sizeof(ftank->color));
} }
return 1; return 1;
} }
void void print_header(FILE *f, struct tanks_game *game, int seed) {
print_header(FILE *f,
struct tanks_game *game,
int seed)
{
fprintf(f, "{\n"); fprintf(f, "{\n");
fprintf(f, " \"seed\": %d,\n", seed); fprintf(f, " \"seed\": %d,\n", seed);
fprintf(f, " \"field\": [%d,%d],\n", (int)game->size[0], (int)game->size[1]); fprintf(f, " \"field\": [%d,%d],\n", (int)game->size[0], (int)game->size[1]);
} }
void void print_rounds(FILE *f, struct tanks_game *game, struct tank *tanks,
print_rounds(FILE *f, int ntanks) {
struct tanks_game *game,
struct tank *tanks,
int ntanks)
{
int alive; int alive;
fprintf(f, " \"rounds\": [\n"); fprintf(f, " \"rounds\": [\n");
@ -395,7 +342,7 @@ print_rounds(FILE *f,
struct tank *t = &(tanks[j]); struct tank *t = &(tanks[j]);
int k; int k;
int flags = 0; int flags = 0;
int sensors = 0; int sensors = 0;
if (j > 0) { if (j > 0) {
@ -417,12 +364,8 @@ print_rounds(FILE *f,
alive -= 1; alive -= 1;
flags |= 4; flags |= 4;
} }
fprintf(f, "[%d,%d,%.2f,%.2f,%d,%d]", fprintf(f, "[%d,%d,%.2f,%.2f,%d,%d]", (int)t->position[0],
(int)t->position[0], (int)(t->position[1]), t->angle, t->turret.current, flags,
(int)(t->position[1]),
t->angle,
t->turret.current,
flags,
sensors); sensors);
} }
fprintf(f, "]"); fprintf(f, "]");
@ -431,12 +374,8 @@ print_rounds(FILE *f,
fprintf(f, "\n ],\n"); fprintf(f, "\n ],\n");
} }
void void print_standings(FILE *f, struct forftank *ftanks, struct tank *tanks,
print_standings(FILE *f, int ntanks) {
struct forftank *ftanks,
struct tank *tanks,
int ntanks)
{
fprintf(f, " \"tanks\": [\n"); fprintf(f, " \"tanks\": [\n");
for (int i = 0; i < ntanks; i += 1) { for (int i = 0; i < ntanks; i += 1) {
@ -462,7 +401,8 @@ print_standings(FILE *f,
fprintf(f, " \"killer\": %d,\n", killer); fprintf(f, " \"killer\": %d,\n", killer);
fprintf(f, " \"kills\": %d,\n", kills); fprintf(f, " \"kills\": %d,\n", kills);
fprintf(f, " \"errorPos\": %d,\n", ftanks[i].error_pos); fprintf(f, " \"errorPos\": %d,\n", ftanks[i].error_pos);
fprintf(f, " \"error\": \"%s\",\n", forf_error_str[ftanks[i].env.error]); fprintf(f, " \"error\": \"%s\",\n",
forf_error_str[ftanks[i].env.error]);
fprintf(f, " \"sensors\": [\n"); fprintf(f, " \"sensors\": [\n");
for (int j = 0; j < TANK_MAX_SENSORS; j += 1) { for (int j = 0; j < TANK_MAX_SENSORS; j += 1) {
struct sensor *s = &(tanks[i].sensors[j]); struct sensor *s = &(tanks[i].sensors[j]);
@ -470,15 +410,15 @@ print_standings(FILE *f,
if (j > 0) { if (j > 0) {
fprintf(f, ",\n"); fprintf(f, ",\n");
} }
if (! s->range) { if (!s->range) {
fprintf(f, " null"); fprintf(f, " null");
} else { } else {
fprintf(f, " {\"range\":%d,\"angle\":%.2f,\"width\":%.2f,\"turret\":%s}", fprintf(f,
(int)(s->range), " "
s->angle, "{\"range\":%d,\"angle\":%.2f,\"width\":%.2f,\"turret\":%s}",
s->width, (int)(s->range), s->angle, s->width,
s->turret?"true":"false"); s->turret ? "true" : "false");
} }
} }
fprintf(f, "\n ]"); fprintf(f, "\n ]");
@ -488,39 +428,36 @@ print_standings(FILE *f,
fprintf(f, "\n ],\n"); fprintf(f, "\n ],\n");
} }
void void print_footer(FILE *f) {
print_footer(FILE *f) fprintf(f,
{ " \"\": null\n"); // sentry, so everything prior can end with a comma
fprintf(f, " \"\": null\n"); // sentry, so everything prior can end with a comma
fprintf(f, "}\n"); fprintf(f, "}\n");
} }
int int main(int argc, char *argv[]) {
main(int argc, char *argv[]) struct tanks_game game;
{ struct forftank myftanks[MAX_TANKS];
struct tanks_game game; struct tank mytanks[MAX_TANKS];
struct forftank myftanks[MAX_TANKS];
struct tank mytanks[MAX_TANKS];
struct forf_lexical_env lenv[LENV_SIZE]; struct forf_lexical_env lenv[LENV_SIZE];
int order[MAX_TANKS]; int order[MAX_TANKS];
int ntanks = 0; int ntanks = 0;
int i; int i;
int seed; int seed;
lenv[0].name = NULL; lenv[0].name = NULL;
lenv[0].proc = NULL; lenv[0].proc = NULL;
if ((! forf_extend_lexical_env(lenv, forf_base_lexical_env, LENV_SIZE)) || if ((!forf_extend_lexical_env(lenv, forf_base_lexical_env, LENV_SIZE)) ||
(! forf_extend_lexical_env(lenv, tanks_lenv_addons, LENV_SIZE))) { (!forf_extend_lexical_env(lenv, tanks_lenv_addons, LENV_SIZE))) {
fprintf(stderr, "Unable to initialize lexical environment.\n"); fprintf(stderr, "Unable to initialize lexical environment.\n");
return 1; return 1;
} }
/* We only need slightly random numbers */ /* We only need slightly random numbers */
{ {
char *s = getenv("SEED"); char *s = getenv("SEED");
seed = atoi(s?s:""); seed = atoi(s ? s : "");
if (! seed) { if (!seed) {
seed = getpid(); seed = getpid();
} }
@ -534,10 +471,7 @@ main(int argc, char *argv[])
/* Every argument is a tank directory */ /* Every argument is a tank directory */
for (i = 1; ntanks < MAX_TANKS && i < argc; i += 1) { for (i = 1; ntanks < MAX_TANKS && i < argc; i += 1) {
if (ft_read_tank(&myftanks[ntanks], if (ft_read_tank(&myftanks[ntanks], &mytanks[ntanks], lenv, argv[i])) {
&mytanks[ntanks],
lenv,
argv[i])) {
ntanks += 1; ntanks += 1;
} }
} }
@ -546,7 +480,8 @@ main(int argc, char *argv[])
{ {
int x, y; int x, y;
for (x = 1; x * x < ntanks; x += 1); for (x = 1; x * x < ntanks; x += 1)
;
y = ntanks / x; y = ntanks / x;
if (ntanks % x) { if (ntanks % x) {
y += 1; y += 1;
@ -570,8 +505,8 @@ main(int argc, char *argv[])
/* Position tanks */ /* Position tanks */
{ {
int x = SPACING/2; int x = SPACING / 2;
int y = SPACING/2; int y = SPACING / 2;
for (i = 0; i < ntanks; i += 1) { for (i = 0; i < ntanks; i += 1) {
mytanks[order[i]].position[0] = (float)x; mytanks[order[i]].position[0] = (float)x;