#if 0
gcc -s -O2 -c -Wno-unused-result class.c `sdl-config --cflags`
exit
#endif
/*
This program is part of Free Hero Mesh and is public domain.
*/
#define HEROMESH_CLASS
#include "SDL.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#include "smallxrm.h"
#include "heromesh.h"
#define TF_COMMA 0x0001
#define TF_EQUAL 0x0002
#define TF_ABNORMAL 0x0004
#define TF_COMPAT 0x0008
#define TF_DIR 0x0010
#define TF_DROP 0x0020
#define TF_NAME 0x0080
#define TF_KEY 0x0100
#define TF_STRING 0x0200
#define TF_OPEN 0x0400
#define TF_CLOSE 0x0800
#define TF_INT 0x1000
#define TF_MACRO 0x4000
#define TF_EOF 0x8000
typedef struct {
const char*txt;
Uint32 num;
} Op_Names;
#include "instruc.h"
Class*classes[0x4000];
const char*messages[0x4000];
int max_animation=32;
Sint32 max_volume=10000;
static FILE*classfp;
static Uint16 tokent;
static Uint32 tokenv;
static int linenum=1;
static char tokenstr[0x2000];
static int undef_class=1;
static int undef_message=0;
#define ParseError(a,...) fatal("On line %d: " a,linenum,##__VA_ARGS__)
static const unsigned char chkind[256]={
['$']=1, ['!']=1, ['\'']=1, ['#']=1, ['@']=1, ['%']=1, ['&']=1, [':']=1,
['0'...'9']=2, ['-']=2, ['+']=2,
['A'...'Z']=3, ['a'...'z']=3, ['_']=3, ['?']=3, ['.']=3, ['*']=3, ['/']=3,
};
static void read_quoted_string(void) {
int c,i,n;
int isimg=0;
for(i=0;i<0x1FFD;) {
c=fgetc(classfp);
if(c==EOF) {
ParseError("Unterminated string literal\n");
} else if(c=='\\') {
if(isimg) {
isimg=0;
tokenstr[i++]=c;
} else switch(c=fgetc(classfp)) {
case '"': case '\\': tokenstr[i++]=c; break;
case '0' ... '7': tokenstr[i++]=c+1-'0'; break;
case 'b': tokenstr[i++]=15; break;
case 'c': tokenstr[i++]=12; break;
case 'i': tokenstr[i++]=14; isimg=1; break;
case 'l': tokenstr[i++]=11; break;
case 'n': tokenstr[i++]=10; break;
case 'q': tokenstr[i++]=16; break;
case 'x':
c=fgetc(classfp);
if(c>='0' && c<='9') n=c-'0';
else if(c>='A' && c<='F') n=c+10-'A';
else if(c>='a' && c<='f') n=c+10-'a';
else ParseError("Invalid string escape: \\x%c\n",c);
n<<=4;
c=fgetc(classfp);
if(c>='0' && c<='9') n|=c-'0';
else if(c>='A' && c<='F') n|=c+10-'A';
else if(c>='a' && c<='f') n|=c+10-'a';
else ParseError("Invalid string escape: \\x%X%c\n",n>>4,c);
if(n<32) tokenstr[i++]=31;
tokenstr[i++]=n;
break;
default: ParseError("Invalid string escape: \\%c\n",c);
}
} else if(c=='"') {
if(isimg) ParseError("Unterminated \\i escape in string literal\n");
tokenstr[i]=0;
return;
} else if(c!='\r') {
tokenstr[i++]=c;
if(c=='\n') ++linenum;
}
}
ParseError("Too long string literal\n");
}
static int name_compar(const void*a,const void*b) {
const Op_Names*x=a;
const Op_Names*y=b;
return strcmp(x->txt,y->txt);
}
#define ReturnToken(x,y) do{ tokent=x; tokenv=y; return; }while(0)
static void nxttok(void) {
int c,i;
int fl=0;
int n=0;
int pr=0;
tokent=tokenv=0;
*tokenstr=0;
again:
c=fgetc(classfp);
while(c==' ' || c=='\t' || c=='\r' || c=='\n') {
if(c=='\n') ++linenum;
c=fgetc(classfp);
}
if(c==EOF) ReturnToken(TF_EOF,0);
if(c==';') {
while(c!=EOF && c!='\n') c=fgetc(classfp);
++linenum;
goto again;
}
if(c=='(') ReturnToken(TF_OPEN,0);
if(c==')') ReturnToken(TF_CLOSE,0);
if(c=='"') {
tokent=TF_STRING;
read_quoted_string();
return;
}
if(c=='=') {
fl|=TF_EQUAL;
c=fgetc(classfp);
}
if(c==',') {
fl|=TF_COMMA;
c=fgetc(classfp);
}
if(c==EOF) ParseError("Unexpected end of file\n");
if(chkind[c]==1) {
pr=c;
c=fgetc(classfp);
if(c==EOF) ParseError("Unexpected end of file\n");
}
while(c>0 && (chkind[c]&2)) {
if(n==256) {
tokenstr[256]=0;
ParseError("Identifier too long: %s\n",tokenstr);
}
tokenstr[n++]=c;
c=fgetc(classfp);
}
tokenstr[n]=0;
if(!n) fatal("Expected identifier\n");
if(c!=EOF) ungetc(c,classfp);
switch(pr) {
case 0:
if(chkind[c=*tokenstr]==2) {
char*e;
if(c=='-' || c=='+') n=1; else n=0;
if(n && !tokenstr[1]) goto norm;
tokent=TF_INT;
if(fl) ParseError("Invalid use of , and = in a numeric token\n");
if(c=='0' && tokenstr[1]=='x') {
tokenv=strtol(tokenstr+2,&e,16);
} else if(c=='0' && tokenstr[1]=='o') {
tokenv=strtol(tokenstr+2,&e,8);
} else {
tokenv=strtol(tokenstr+n,&e,10);
}
if(e && *e) ParseError("Invalid token: %s\n",tokenstr);
if(c=='-') tokenv=-tokenv;
} else {
static Op_Names key={tokenstr};
const Op_Names*op;
norm:
op=bsearch(&key,op_names,N_OP_NAMES,sizeof(Op_Names),name_compar);
if(!op) ParseError("Invalid token: %s\n",tokenstr);
tokenv=op->num&0xFFFF;
tokent=op->num>>16;
if(fl&~tokent) ParseError("Invalid use of , and = in token: %s\n",tokenstr);
}
break;
case '$':
break;
case '!':
// Just ignore sounds for now
if(fl) ParseError("Invalid use of , and = in user sound token\n");
tokent=TF_NAME;
tokenv=0x0400;
break;
case '%':
break;
case '@':
break;
case '#':
break;
case ':':
break;
case '&':
break;
case '\'':
break;
}
}
void load_classes(void) {
}