mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-21 18:30:52 +00:00
Added support for some modelgen/spritegen commands
This commit is contained in:
parent
91ee7658a6
commit
e00c8da849
4 changed files with 161 additions and 2 deletions
|
@ -11,6 +11,9 @@ void(entity) kill = #4;
|
|||
.float mema;
|
||||
.float memb;
|
||||
|
||||
$framevalue 37
|
||||
$frame stand1 stand2 stand3
|
||||
|
||||
void() main = {
|
||||
entity pawn;
|
||||
vector vec;
|
||||
|
@ -59,4 +62,5 @@ void() main = {
|
|||
print3("memb = ", ftos(pawn.memb), "\n");
|
||||
pawn.memb += -1;
|
||||
print3("memb = ", ftos(pawn.memb), "\n");
|
||||
print3("Frame stand3 is ", ftos(stand3), " wooh\n");
|
||||
};
|
||||
|
|
144
lexer.c
144
lexer.c
|
@ -7,6 +7,7 @@
|
|||
#include "lexer.h"
|
||||
|
||||
MEM_VEC_FUNCTIONS(token, char, value)
|
||||
MEM_VEC_FUNCTIONS(lex_file, frame_macro, frames)
|
||||
|
||||
void lexerror(lex_file *lex, const char *fmt, ...)
|
||||
{
|
||||
|
@ -342,6 +343,58 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* read one ident for the frame list */
|
||||
static int lex_parse_frame(lex_file *lex)
|
||||
{
|
||||
int ch;
|
||||
|
||||
if (lex->tok)
|
||||
token_delete(lex->tok);
|
||||
lex->tok = token_new();
|
||||
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && ch != '\n' && isspace(ch))
|
||||
ch = lex_getch(lex);
|
||||
|
||||
if (ch == '\n')
|
||||
return 1;
|
||||
|
||||
if (!isident_start(ch)) {
|
||||
lexerror(lex, "invalid framename, must start with one of a-z or _, got %c", ch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!lex_tokench(lex, ch))
|
||||
return -1;
|
||||
if (!lex_finish_ident(lex))
|
||||
return -1;
|
||||
if (!lex_endtoken(lex))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read a list of $frames */
|
||||
static bool lex_finish_frames(lex_file *lex)
|
||||
{
|
||||
do {
|
||||
int rc;
|
||||
frame_macro m;
|
||||
|
||||
rc = lex_parse_frame(lex);
|
||||
if (rc > 0) /* end of line */
|
||||
return true;
|
||||
if (rc < 0) /* error */
|
||||
return false;
|
||||
|
||||
m.value = lex->framevalue++;
|
||||
m.name = util_strdup(lex->tok->value);
|
||||
if (!m.name || !lex_file_frames_add(lex, m)) {
|
||||
lexerror(lex, "out of memory");
|
||||
return false;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
|
||||
{
|
||||
int ch = 0;
|
||||
|
@ -486,6 +539,87 @@ int lex_do(lex_file *lex)
|
|||
if (ch == EOF)
|
||||
return (lex->tok->ttype = TOKEN_EOF);
|
||||
|
||||
/* modelgen / spiritgen commands */
|
||||
if (ch == '$') {
|
||||
const char *v;
|
||||
ch = lex_getch(lex);
|
||||
if (!isident_start(ch)) {
|
||||
lexerror(lex, "hanging '$' modelgen/spritegen command line");
|
||||
return lex_do(lex);
|
||||
}
|
||||
if (!lex_tokench(lex, ch))
|
||||
return (lex->tok->ttype = TOKEN_FATAL);
|
||||
if (!lex_finish_ident(lex))
|
||||
return (lex->tok->ttype = TOKEN_ERROR);
|
||||
if (!lex_endtoken(lex))
|
||||
return (lex->tok->ttype = TOKEN_FATAL);
|
||||
/* skip the known commands */
|
||||
v = lex->tok->value;
|
||||
|
||||
if (!strcmp(v, "frame") || !strcmp(v, "framesave"))
|
||||
{
|
||||
/* frame/framesave command works like an enum
|
||||
* similar to fteqcc we handle this in the lexer.
|
||||
* The reason for this is that it is sensitive to newlines,
|
||||
* which the parser is unaware of
|
||||
*/
|
||||
if (!lex_finish_frames(lex))
|
||||
return (lex->tok->ttype = TOKEN_ERROR);
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
||||
if (!strcmp(v, "framevalue"))
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && isspace(ch) && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
|
||||
if (!isdigit(ch)) {
|
||||
lexerror(lex, "$framevalue requires an integer parameter");
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
||||
token_delete(lex->tok);
|
||||
lex->tok = token_new();
|
||||
lex->tok->ttype = lex_finish_digit(lex, ch);
|
||||
if (!lex_endtoken(lex))
|
||||
return (lex->tok->ttype = TOKEN_FATAL);
|
||||
if (lex->tok->ttype != TOKEN_INTCONST) {
|
||||
lexerror(lex, "$framevalue requires an integer parameter");
|
||||
return lex_do(lex);
|
||||
}
|
||||
lex->framevalue = lex->tok->constval.i;
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
||||
if (!strcmp(v, "flush"))
|
||||
{
|
||||
size_t frame;
|
||||
for (frame = 0; frame < lex->frames_count; ++frame)
|
||||
mem_d(lex->frames[frame].name);
|
||||
MEM_VECTOR_CLEAR(lex, frames);
|
||||
/* skip line (fteqcc does it too) */
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
||||
if (!strcmp(v, "cd") ||
|
||||
!strcmp(v, "origin") ||
|
||||
!strcmp(v, "base") ||
|
||||
!strcmp(v, "flags") ||
|
||||
!strcmp(v, "scale") ||
|
||||
!strcmp(v, "skin"))
|
||||
{
|
||||
/* skip line */
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
return lex_do(lex);
|
||||
}
|
||||
}
|
||||
|
||||
/* single-character tokens */
|
||||
switch (ch)
|
||||
{
|
||||
|
@ -497,8 +631,6 @@ int lex_do(lex_file *lex)
|
|||
case '[':
|
||||
case ']':
|
||||
|
||||
case '$':
|
||||
|
||||
case '#':
|
||||
if (!lex_tokench(lex, ch) ||
|
||||
!lex_endtoken(lex))
|
||||
|
@ -606,6 +738,7 @@ int lex_do(lex_file *lex)
|
|||
if (isident_start(ch))
|
||||
{
|
||||
const char *v;
|
||||
size_t frame;
|
||||
if (!lex_tokench(lex, ch))
|
||||
return (lex->tok->ttype = TOKEN_FATAL);
|
||||
if (!lex_finish_ident(lex)) {
|
||||
|
@ -645,6 +778,13 @@ int lex_do(lex_file *lex)
|
|||
!strcmp(v, "const"))
|
||||
lex->tok->ttype = TOKEN_KEYWORD;
|
||||
|
||||
for (frame = 0; frame < lex->frames_count; ++frame) {
|
||||
if (!strcmp(v, lex->frames[frame].name)) {
|
||||
lex->tok->constval.i = lex->frames[frame].value;
|
||||
return (lex->tok->ttype = TOKEN_INTCONST);
|
||||
}
|
||||
}
|
||||
|
||||
return lex->tok->ttype;
|
||||
}
|
||||
|
||||
|
|
8
lexer.h
8
lexer.h
|
@ -81,6 +81,11 @@ _all_tokennames_added_[
|
|||
(sizeof(_tokennames)/sizeof(_tokennames[0])))
|
||||
? 1 : -1];
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int value;
|
||||
} frame_macro;
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
char *name;
|
||||
|
@ -95,6 +100,9 @@ typedef struct {
|
|||
struct {
|
||||
bool noops;
|
||||
} flags;
|
||||
|
||||
int framevalue;
|
||||
MEM_VECTOR_MAKE(frame_macro, frames);
|
||||
} lex_file;
|
||||
|
||||
MEM_VECTOR_PROTO(lex_file, char, token);
|
||||
|
|
7
parser.c
7
parser.c
|
@ -2160,6 +2160,13 @@ nextfield:
|
|||
|
||||
return true;
|
||||
}
|
||||
else if (parser->tok == '$')
|
||||
{
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "parse error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parseerror(parser, "unexpected token: %s", parser->lex->tok->value);
|
||||
|
|
Loading…
Reference in a new issue