home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Archived
/
Updates
/
Flash
/
writeflash
/
!MakeFlash
/
c
/
preproces2
< prev
next >
Wrap
Text File
|
2000-04-21
|
13KB
|
553 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <ctype.h>
#include "proto.h"
#include "main.h"
#include "preprocess.h"
#include "evaluate.h"
#define MACRONAME 0
#define MACROVALUE 1
#define LOOPNAME_FIRST 'a'
#define LOOPNAME_LAST 'z'
typedef struct loop {
U32 startoffset;
S32 current;
char name[MAXVARNAMELENGTH+1];
char *to_expr;
} loop;
static loop loopinfo[LOOPNAME_LAST-LOOPNAME_FIRST+1];
static int loopdepth = 0;
static char *macros[MAXMACROS][2];
static int macrocount = 0;
static U32 allocated, codesize, ifdefdepth, readoffset;
static char *buffer;
static int define_macro(char *line);
static int insert_file(char *filename);
static int macro_substitute(char *line, char *out);
static int is_macro_start_char(char s);
static int is_macro_char(char s);
static int insert_line(char *line);
static int read_line(char *line);
static void strip_leading_trailing_spaces(char *in, char **out);
static char *get_var_name(char *in, char *name);
int preprocessor(char *filename) {
int i;
buffer = malloc(32*1024);
if (!buffer) {
fprintf(stderr, "No room\n");
return 1;
}
allocated = 32*1024;
codesize = 0;
macrocount = 0;
ifdefdepth = 0;
readoffset = 0;
loopdepth = 0;
for (i = 0; i < LOOPNAME_LAST-LOOPNAME_FIRST+1; i++)
loopinfo[i].name[0] = '\0';
return insert_file(filename);
}
int end_of_file() {
if (readoffset >= codesize) return 1;
return 0;
}
int get_line(char *line) {
U32 old;
old = readoffset;
if (read_line(line)) return 1;
if (strncmp(line, ":for ", 5) == 0) {
char name[2], expr1[MAXLINELENGTH], expr2[MAXLINELENGTH];
if (sscanf(line+5, "%1s = %s to %s", name, expr1, expr2) == 3) {
if ((strlen(name) != 1) || (loopdepth > LOOPNAME_LAST-LOOPNAME_FIRST) ||
(name[0] < LOOPNAME_FIRST) || (name[0] > LOOPNAME_LAST)) {
fprintf(stderr, "Bad variable name or too many nested loops\n");
return 1;
}
if (loopinfo[loopdepth].name[0]) {
fprintf(stderr, "Variable '%s' already used\n", name);
return 1;
}
if (evaluate(expr1, &loopinfo[loopdepth].current)) return 1;
loopinfo[loopdepth].to_expr = malloc(strlen(expr2)+1);
if (!loopinfo[loopdepth].to_expr) {
fprintf(stderr, "No room\n");
return 1;
}
strcpy(loopinfo[loopdepth].to_expr, expr2);
if (create_variable(name)) return 1;
if (set_variable_value(name, loopinfo[loopdepth].current)) return 1;
loopinfo[loopdepth].startoffset = readoffset;
strcpy(loopinfo[loopdepth].name, name);
loopdepth++;
return get_line(line);
} else {
fprintf(stderr, "Bad ':for' instruction\n");
return 1;
}
} else if (strncmp(line, ":next", 5) == 0) {
S32 to;
if (loopdepth == 0) {
fprintf(stderr, "Unmatched ':next' encountered\n");
return 1;
}
loopinfo[loopdepth-1].current++;
if (set_variable_value(loopinfo[loopdepth-1].name,
loopinfo[loopdepth-1].current)) return 1;
if (evaluate(loopinfo[loopdepth-1].to_expr, &to)) return 1;
if (loopinfo[loopdepth-1].current <= to) {
readoffset = loopinfo[loopdepth-1].startoffset;
return get_line(line);
} else {
loopdepth--;
if (destroy_variable(loopinfo[loopdepth].name)) return 1;
free(loopinfo[loopdepth].to_expr);
loopinfo[loopdepth].name[0] = '\0';
return get_line(line);
}
} else if (strncmp(line, ":print ", 7) == 0) {
char *p;
strip_leading_trailing_spaces(line+7, &p);
if (*p == '"') {
char *end;
end = p + strlen(p) - 1;
if (*end != '"') {
fprintf(stderr, "Bad ':print'\n");
return 1;
}
*end = '\0';
printf("%s\n", p);
} else {
S32 v;
if (evaluate(p, &v)) return 1;
printf("%d\n", v);
}
return get_line(line);
} else if (strncmp(line, ":endif", 6) == 0) {
return get_line(line);
} else if (strncmp(line, ":var ", 5) == 0) {
char *p, name[MAXVARNAMELENGTH+1];
int n;
p = line+5;
n = 0;
do {
p = get_var_name(p, name);
if (!p) {
fprintf(stderr, "Syntax error in ':var'\n");
return 1;
}
if (create_variable(name)) return 1;
n++;
if ((*p) && (*p != ',')) {
fprintf(stderr, "Syntax error in ':var'\n");
return 1;
}
if (*p == ',') {
p++;
while (*p == ' ') p++;
if (!*p) {
fprintf(stderr, "Syntax error in ':var'\n");
return 1;
}
}
} while (*p);
if (!n) {
fprintf(stderr, "Syntax error in ':var'\n");
return 1;
}
return get_line(line);
} else if (strncmp(line, ":if ", 4) == 0) {
S32 value;
if (evaluate(line+4, &value)) {
fprintf(stderr, "Failed to evaluate '%s'\n", line+4);
return 1;
}
if (!value) {
int ifdepth;
ifdepth = 1;
do {
if (read_line(line)) return 1;
if (strncmp(line, ":if ", 4) == 0)
ifdepth++;
if (strncmp(line, ":endif", 6) == 0)
ifdepth--;
} while (ifdepth);
}
return get_line(line);
} else if (line[0] == ':') {
char name[MAXVARNAMELENGTH+1], *p;
S32 value, varvalue;
int error;
p = get_var_name(line+1, name);
if (!p) {
fprintf(stderr, "Syntax error: '%s'\n", line);
return 1;
}
if (read_variable_value(name, &varvalue)) return 1;
while (*p == ' ') p++;
error = 0;
if ((p[0] == '+') && (p[1] == '=')) {
error = evaluate(p+2, &value);
varvalue += value;
} else if ((p[0] == '-') && (p[1] == '=')) {
error = evaluate(p+2, &value);
varvalue -= value;
} else if ((p[0] == '*') && (p[1] == '=')) {
error = evaluate(p+2, &value);
varvalue *= value;
} else if ((p[0] == '/') && (p[1] == '=')) {
error = evaluate(p+2, &value);
if (value == 0) {
fprintf(stderr, "Division by zero: %s equals 0\n", p+2);
return 1;
}
varvalue /= value;
} else if (p[0] == '=') {
error = evaluate(p+1, &varvalue);
}
if (error) {
fprintf(stderr, "Syntax error: '%s'\n", line);
return 1;
}
if (set_variable_value(name, varvalue)) return 1;
return get_line(line);
} else if (line[0] == '.') {
fprintf(stderr, "Lines are not allowed to start with a '.'\n");
return 1;
}
return 0;
}
int find_macro(char *name) {
int i;
char *p;
while (isspace(name[0])) name++;
p = name;
while (is_macro_char(*p)) p++;
*p = '\0';
for (i = 0; i < macrocount; i++)
if (strcmp(macros[i][MACRONAME], name) == 0) return i;
return -1;
}
// --------------------------------------------------------------------
int is_macro_start_char(char s) {
if (isalpha(s) || (s == '_')) return 1;
return 0;
}
int is_macro_char(char s) {
if (isalpha(s) || isdigit(s) || (s == '_')) return 1;
return 0;
}
int insert_file(char *filename) {
FILE *fh;
char line[MAXLINELENGTH];
fh = fopen(filename, "r");
if (!fh) {
fprintf(stderr, "Failed to open file '%s'\n", filename);
return 1;
}
do {
if (fgets(line, MAXLINELENGTH, fh)) {
int i;
// convert TAB, linefeed etc to normal spaces
for(i = 0; i < strlen(line); i++)
if (line[i] < ' ') line[i] = ' ';
if (line[0] == '#') {
if (strncmp(line, "#define ", 8) == 0) {
if (!ifdefdepth) {
char temp[MAXLINELENGTH];
if (macro_substitute(line+8, temp)) return 1;
if (define_macro(temp)) return 1;
}
} else if (strncmp(line, "#undef ", 7) == 0) {
if (!ifdefdepth) {
int mi;
mi = find_macro(line+7);
if (mi >= 0) {
if (mi != macrocount-1) {
macros[mi][MACRONAME] = macros[macrocount-1][MACRONAME];
macros[mi][MACROVALUE] = macros[macrocount-1][MACROVALUE];
}
macrocount--;
}
}
} else if (strncmp(line, "#ifdef ", 7) == 0) {
if (ifdefdepth)
ifdefdepth++;
else {
if (find_macro(line+7) < 0) ifdefdepth++;
}
} else if (strncmp(line, "#else", 5) == 0) {
if (ifdefdepth == 1)
ifdefdepth = 0;
else if (ifdefdepth == 0)
ifdefdepth = 1;
} else if (strncmp(line, "#ifndef ", 8) == 0) {
if (ifdefdepth)
ifdefdepth++;
else {
if (find_macro(line+8) >= 0) ifdefdepth++;
}
} else if (strncmp(line, "#endif", 6) == 0) {
if (ifdefdepth) ifdefdepth--;
} else if (strncmp(line, "#include ", 9) == 0) {
if (!ifdefdepth) {
char *filename;
strip_leading_trailing_spaces(line+9, &filename);
if (insert_file(filename)) {
fclose(fh);
return 1;
}
}
} else if (!ifdefdepth) {
if (insert_line(line)) {
fclose(fh);
return 1;
}
}
} else if (!ifdefdepth) {
char output[MAXLINELENGTH];
if (macro_substitute(line, output)) {
fclose(fh);
return 1;
}
if (insert_line(output)) {
fclose(fh);
return 1;
}
}
} else {
fclose(fh);
return 0;
}
} while (fh);
return 1;
}
int insert_line(char *line) {
int len;
len = strlen(line)+1;
if (codesize + len >= allocated) {
char *newbuffer;
newbuffer = realloc(buffer, allocated + 32*1024);
if (!newbuffer) return 1;
allocated += 32*1024;
buffer = newbuffer;
}
memcpy(buffer+codesize, line, len);
codesize += len;
return 0;
}
int define_macro(char *line) {
char macro[256], *value;
int p, l;
if (macrocount == MAXMACROS) {
fprintf(stderr, "Too many macros\n");
return 1;
}
p = 0;
while ((line[p] <= ' ') && (line[p])) p++;
l = 0;
while ((is_macro_char(line[p])) && (l < 255)) macro[l++] = line[p++];
macro[l] = '\0';
if ((line[p] != ' ') || (l >= 256)) {
fprintf(stderr, "Illegal macro definition: #define %s\n", line);
return 1;
}
strip_leading_trailing_spaces(line+p, &value);
if (!is_macro_start_char(macro[0])) {
fprintf(stderr, "Illegal macro name '%s'\n", macro);
return 1;
}
if (find_macro(macro) != -1) {
fprintf(stderr, "Dublicate definition of macro '%s'\n", macro);
return 1;
}
macros[macrocount][MACRONAME] = malloc(strlen(macro)+1);
if (!macros[macrocount][MACRONAME]) {
fprintf(stderr, "No room for macro\n");
return 1;
}
strcpy(macros[macrocount][MACRONAME], macro);
macros[macrocount][MACROVALUE] = malloc(strlen(value)+1);
if (!macros[macrocount][MACROVALUE]) {
fprintf(stderr, "No room for macro\n");
return 1;
}
strcpy(macros[macrocount][MACROVALUE], value);
macrocount++;
return 0;
}
int macro_substitute(char *line, char *out) {
int rd, wr, len, checkmacro;
len = strlen(line);
checkmacro = 1;
wr = 0;
for (rd = 0; rd < len; rd++) {
if ((checkmacro) && (is_macro_start_char(line[rd]))) {
int m;
for (m = 0; m < macrocount; m++) {
char *macro, *value;
int len;
macro = macros[m][MACRONAME];
value = macros[m][MACROVALUE];
len = strlen(macro);
if ((strncmp(line+rd, macro, len) == 0) && (!is_macro_char(line[rd+len]))) {
if (wr + strlen(value) > MAXLINELENGTH-1) {
fprintf(stderr, "Macro-substituted line is too long\n");
return 1;
}
strcpy(out+wr, value);
wr += strlen(value);
rd += strlen(macro);
m = macrocount+1; // abort
rd--;
}
}
if (m == macrocount) out[wr++] = line[rd];
checkmacro = 0;
} else {
if (!is_macro_char(line[rd]))
checkmacro = 1;
else
checkmacro = 0;
out[wr++] = line[rd];
}
}
out[wr] = '\0';
return 0;
}
int read_line(char *line) {
if (readoffset >= codesize) return 1;
strcpy(line, buffer+readoffset);
readoffset += strlen(line)+1;
return 0;
}
void strip_leading_trailing_spaces(char *in, char **out) {
while (*in == ' ') in++;
*out = in;
if (!*in) return;
in += strlen(in)-1;
while (*in == ' ') *in = '\0', in--;
}
char *get_var_name(char *in, char *name) {
int len;
while (*in == ' ') in++;
if (!is_macro_start_char(*in)) return NULL;
len = 0;
while ((len < MAXVARNAMELENGTH) && (is_macro_char(*in)))
name[len++] = *in++;
if (len > MAXVARNAMELENGTH) return NULL;
name[len] = '\0';
while (*in == ' ') in++;
return in;
}