mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +00:00
Embedded commands now work without any bugs I can detect. Next up are
loops, branching, and getting the tokenizer to give special treatment to certain builtin functions. But first I should get some sleep :)
This commit is contained in:
parent
bd9092a626
commit
666c3fce07
8 changed files with 109 additions and 32 deletions
|
@ -40,9 +40,13 @@ typedef struct gib_buffer_data_s {
|
||||||
|
|
||||||
// Data for handling return values
|
// Data for handling return values
|
||||||
struct {
|
struct {
|
||||||
qboolean waiting, available;
|
qboolean waiting, available; // Return value states
|
||||||
|
|
||||||
|
// Data saved by tokenizer/processor
|
||||||
unsigned int line_pos; // Position within line
|
unsigned int line_pos; // Position within line
|
||||||
unsigned int token_pos; // Position within token
|
unsigned int token_pos; // Position within token
|
||||||
|
qboolean cat; // Concatenate to previous token?
|
||||||
|
char delim; // delimiter of token
|
||||||
struct dstring_s *retval; // Returned value
|
struct dstring_s *retval; // Returned value
|
||||||
} ret;
|
} ret;
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
char GIB_Parse_Match_Angle (const char *str, unsigned int *i);
|
||||||
|
|
||||||
void GIB_Parse_Extract_Line (struct cbuf_s *cbuf);
|
void GIB_Parse_Extract_Line (struct cbuf_s *cbuf);
|
||||||
void GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf);
|
void GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf);
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ Cbuf_Execute (cbuf_t *cbuf)
|
||||||
{
|
{
|
||||||
cbuf_active = cbuf;
|
cbuf_active = cbuf;
|
||||||
cbuf->state = CBUF_STATE_NORMAL;
|
cbuf->state = CBUF_STATE_NORMAL;
|
||||||
while (cbuf->buf->str[0]) {
|
while (cbuf->buf->str[0] || cbuf->line->str[0]) {
|
||||||
cbuf->interpreter->extract_line (cbuf);
|
cbuf->interpreter->extract_line (cbuf);
|
||||||
if (cbuf->state)
|
if (cbuf->state)
|
||||||
break;
|
break;
|
||||||
|
@ -185,6 +185,7 @@ Cbuf_Execute_Stack (cbuf_t *cbuf)
|
||||||
sp = sp->up;
|
sp = sp->up;
|
||||||
}
|
}
|
||||||
dstring_clearstr (cbuf->buf);
|
dstring_clearstr (cbuf->buf);
|
||||||
|
dstring_clearstr (cbuf->line);
|
||||||
if (cbuf->down) {
|
if (cbuf->down) {
|
||||||
Cbuf_DeleteStack (cbuf->down);
|
Cbuf_DeleteStack (cbuf->down);
|
||||||
cbuf->down = 0;
|
cbuf->down = 0;
|
||||||
|
@ -197,7 +198,7 @@ Cbuf_Execute_Sets (cbuf_t *cbuf)
|
||||||
cbuf_args_t *args = cbuf->args;
|
cbuf_args_t *args = cbuf->args;
|
||||||
|
|
||||||
cbuf_active = cbuf;
|
cbuf_active = cbuf;
|
||||||
while (cbuf->buf->str[0]) {
|
while (cbuf->buf->str[0] || cbuf->line->str[0]) {
|
||||||
cbuf->interpreter->extract_line (cbuf);
|
cbuf->interpreter->extract_line (cbuf);
|
||||||
cbuf->interpreter->parse_line (cbuf);
|
cbuf->interpreter->parse_line (cbuf);
|
||||||
if (!args->argc)
|
if (!args->argc)
|
||||||
|
|
|
@ -92,13 +92,15 @@ void GIB_Buffer_Construct (struct cbuf_s *cbuf)
|
||||||
cbuf->data = calloc (1, sizeof (gib_buffer_data_t));
|
cbuf->data = calloc (1, sizeof (gib_buffer_data_t));
|
||||||
GIB_DATA (cbuf)->arg_composite = dstring_newstr ();
|
GIB_DATA (cbuf)->arg_composite = dstring_newstr ();
|
||||||
GIB_DATA (cbuf)->current_token = dstring_newstr ();
|
GIB_DATA (cbuf)->current_token = dstring_newstr ();
|
||||||
|
GIB_DATA (cbuf)->ret.retval = dstring_newstr ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GIB_Buffer_Destruct (struct cbuf_s *cbuf)
|
void GIB_Buffer_Destruct (struct cbuf_s *cbuf)
|
||||||
{
|
{
|
||||||
dstring_delete (GIB_DATA (cbuf)->arg_composite);
|
dstring_delete (GIB_DATA (cbuf)->arg_composite);
|
||||||
dstring_delete (GIB_DATA (cbuf)->current_token);
|
dstring_delete (GIB_DATA (cbuf)->current_token);
|
||||||
if (GIB_DATA(cbuf)->locals)
|
dstring_delete (GIB_DATA (cbuf)->ret.retval);
|
||||||
|
if (GIB_DATA(cbuf)->locals && GIB_DATA(cbuf)->type == GIB_BUFFER_NORMAL)
|
||||||
Hash_DelTable (GIB_DATA(cbuf)->locals);
|
Hash_DelTable (GIB_DATA(cbuf)->locals);
|
||||||
free (cbuf->data);
|
free (cbuf->data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,9 +116,31 @@ GIB_Lset_f (void)
|
||||||
GIB_Local_Set (cbuf_active, GIB_Argv(1), GIB_Argv(2));
|
GIB_Local_Set (cbuf_active, GIB_Argv(1), GIB_Argv(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GIB_Return_f (void)
|
||||||
|
{
|
||||||
|
if (GIB_Argc () > 2)
|
||||||
|
Cbuf_Error ("numargs",
|
||||||
|
"return: invalid number of arguments\n"
|
||||||
|
"usage: return <value>");
|
||||||
|
else {
|
||||||
|
dstring_clearstr (cbuf_active->buf);
|
||||||
|
if (GIB_Argc () == 1)
|
||||||
|
return;
|
||||||
|
if (!cbuf_active->up || !cbuf_active->up->up)
|
||||||
|
Cbuf_Error ("return","return attempted at top of stack");
|
||||||
|
if (GIB_DATA(cbuf_active->up->up)->ret.waiting) {
|
||||||
|
dstring_clearstr (GIB_DATA(cbuf_active->up->up)->ret.retval);
|
||||||
|
dstring_appendstr (GIB_DATA(cbuf_active->up->up)->ret.retval, GIB_Argv(1));
|
||||||
|
GIB_DATA(cbuf_active->up->up)->ret.available = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GIB_Builtin_Init (void)
|
GIB_Builtin_Init (void)
|
||||||
{
|
{
|
||||||
GIB_Builtin_Add ("function", GIB_Function_f);
|
GIB_Builtin_Add ("function", GIB_Function_f);
|
||||||
GIB_Builtin_Add ("lset", GIB_Lset_f);
|
GIB_Builtin_Add ("lset", GIB_Lset_f);
|
||||||
|
GIB_Builtin_Add ("return", GIB_Return_f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ GIB_Parse_Match_Dquote (const char *str, unsigned int *i)
|
||||||
for ((*i)++; str[*i]; (*i)++) {
|
for ((*i)++; str[*i]; (*i)++) {
|
||||||
if (str[*i] == '\n')
|
if (str[*i] == '\n')
|
||||||
return '\"'; // Newlines should never occur inside quotes, EVER
|
return '\"'; // Newlines should never occur inside quotes, EVER
|
||||||
if (str[*i] == '\"')
|
else if (str[*i] == '\"')
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return '\"';
|
return '\"';
|
||||||
|
@ -77,12 +77,10 @@ GIB_Parse_Match_Brace (const char *str, unsigned int *i)
|
||||||
if (str[*i] == '\"') {
|
if (str[*i] == '\"') {
|
||||||
if ((c = GIB_Parse_Match_Dquote (str, i)))
|
if ((c = GIB_Parse_Match_Dquote (str, i)))
|
||||||
return c;
|
return c;
|
||||||
}
|
} else if (str[*i] == '{') {
|
||||||
if (str[*i] == '{') {
|
|
||||||
if ((c = GIB_Parse_Match_Brace (str, i)))
|
if ((c = GIB_Parse_Match_Brace (str, i)))
|
||||||
return c;
|
return c;
|
||||||
}
|
} else if (str[*i] == '}')
|
||||||
if (str[*i] == '}')
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return '{';
|
return '{';
|
||||||
|
@ -96,8 +94,7 @@ GIB_Parse_Match_Paren (const char *str, unsigned int *i)
|
||||||
if (str[*i] == '(') {
|
if (str[*i] == '(') {
|
||||||
if ((c = GIB_Parse_Match_Paren (str, i)))
|
if ((c = GIB_Parse_Match_Paren (str, i)))
|
||||||
return c;
|
return c;
|
||||||
}
|
} else if (str[*i] == ')')
|
||||||
if (str[*i] == ')')
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return '(';
|
return '(';
|
||||||
|
@ -264,9 +261,9 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf)
|
||||||
dstring_t *arg = GIB_DATA(cbuf)->current_token;
|
dstring_t *arg = GIB_DATA(cbuf)->current_token;
|
||||||
const char *str = cbuf->line->str;
|
const char *str = cbuf->line->str;
|
||||||
cbuf_args_t *args = cbuf->args;
|
cbuf_args_t *args = cbuf->args;
|
||||||
static qboolean cat = false;
|
qboolean cat = false;
|
||||||
char delim;
|
char delim;
|
||||||
int i = 0;
|
int i;
|
||||||
|
|
||||||
// This function can be interrupted to call a GIB
|
// This function can be interrupted to call a GIB
|
||||||
// subroutine. First we need to clean up anything
|
// subroutine. First we need to clean up anything
|
||||||
|
@ -275,19 +272,15 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf)
|
||||||
// Do we have a left-over token that needs processing?
|
// Do we have a left-over token that needs processing?
|
||||||
|
|
||||||
if (GIB_DATA(cbuf)->ret.waiting) {
|
if (GIB_DATA(cbuf)->ret.waiting) {
|
||||||
// FIXME: Call processing function here
|
if (GIB_Process_Token (arg, GIB_DATA(cbuf)->ret.delim))
|
||||||
if (GIB_DATA(cbuf)->ret.waiting) // Still not done?
|
return; // Still not done, or error
|
||||||
return;
|
GIB_Parse_Add_Token (cbuf->args, GIB_DATA(cbuf)->ret.cat, arg);
|
||||||
i = GIB_DATA(cbuf)->ret.line_pos; // Start where we left off
|
i = GIB_DATA(cbuf)->ret.line_pos; // Start tokenizing where we left off
|
||||||
} else {
|
} else {
|
||||||
args->argc = 0; // Start from scratch
|
args->argc = 0; // Start from scratch
|
||||||
i = 0;
|
i = 0;
|
||||||
cat = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get just the first token so we can look up any
|
|
||||||
// parsing options that a builtin requests
|
|
||||||
|
|
||||||
while (str[i]) {
|
while (str[i]) {
|
||||||
while (isspace(str[i])) // Eliminate whitespace
|
while (isspace(str[i])) // Eliminate whitespace
|
||||||
i++;
|
i++;
|
||||||
|
@ -298,15 +291,14 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf)
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dstring_clearstr (arg);
|
||||||
delim = GIB_Parse_Get_Token (str, &i, arg);
|
delim = GIB_Parse_Get_Token (str, &i, arg);
|
||||||
if (!delim)
|
if (!delim)
|
||||||
break;
|
break;
|
||||||
Sys_DPrintf("Got token: %s\n", arg->str);
|
Sys_DPrintf("Got token: %s\n", arg->str);
|
||||||
|
|
||||||
// FIXME: Command sub goes here with subroutine handling
|
|
||||||
|
|
||||||
if (GIB_Process_Token (arg, delim))
|
if (GIB_Process_Token (arg, delim))
|
||||||
goto FILTER_ERROR;
|
goto FILTER_ERROR; // Error or GIB subroutine needs to be called
|
||||||
|
|
||||||
GIB_Parse_Add_Token (cbuf->args, cat, arg);
|
GIB_Parse_Add_Token (cbuf->args, cat, arg);
|
||||||
if (cat)
|
if (cat)
|
||||||
|
@ -314,13 +306,14 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf)
|
||||||
|
|
||||||
if (delim != ' ') // Move into whitespace if we haven't already
|
if (delim != ' ') // Move into whitespace if we haven't already
|
||||||
i++;
|
i++;
|
||||||
dstring_clearstr (arg);
|
|
||||||
}
|
}
|
||||||
GIB_Parse_Generate_Composite (cbuf);
|
GIB_Parse_Generate_Composite (cbuf);
|
||||||
|
dstring_clearstr (cbuf->line);
|
||||||
return;
|
return;
|
||||||
FILTER_ERROR: // Error during filtering, clean up mess
|
FILTER_ERROR:
|
||||||
dstring_clearstr (arg);
|
GIB_DATA(cbuf)->ret.line_pos = i; // save our information in case
|
||||||
args->argc = 0;
|
GIB_DATA(cbuf)->ret.cat = cat; // error is not fatal
|
||||||
|
GIB_DATA(cbuf)->ret.delim = delim;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "QF/cbuf.h"
|
#include "QF/cbuf.h"
|
||||||
#include "QF/cvar.h"
|
#include "QF/cvar.h"
|
||||||
#include "QF/gib_buffer.h"
|
#include "QF/gib_buffer.h"
|
||||||
|
#include "QF/gib_parse.h"
|
||||||
|
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
|
|
||||||
|
@ -95,12 +96,63 @@ GIB_Process_Math (struct dstring_s *token)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GIB_Process_Embedded (struct dstring_s *token)
|
||||||
|
{
|
||||||
|
cbuf_t *sub;
|
||||||
|
int i, n;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (GIB_DATA(cbuf_active)->ret.waiting) {
|
||||||
|
if (!GIB_DATA(cbuf_active)->ret.available) {
|
||||||
|
GIB_DATA(cbuf_active)->ret.waiting = false;
|
||||||
|
Cbuf_Error ("return", "Embedded command did not return a value.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
i = GIB_DATA(cbuf_active)->ret.token_pos; // Jump to the right place
|
||||||
|
} else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (; token->str[i]; i++) {
|
||||||
|
if (token->str[i] == '<') {
|
||||||
|
n = i;
|
||||||
|
if ((c = GIB_Parse_Match_Angle (token->str, &i))) {
|
||||||
|
Cbuf_Error ("parse", "Could not find matching %c", c);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (GIB_DATA(cbuf_active)->ret.available) {
|
||||||
|
dstring_replace (token, n, i-n+1, GIB_DATA(cbuf_active)->ret.retval->str,
|
||||||
|
strlen(GIB_DATA(cbuf_active)->ret.retval->str));
|
||||||
|
i = n + strlen(GIB_DATA(cbuf_active)->ret.retval->str) - 1;
|
||||||
|
GIB_DATA(cbuf_active)->ret.waiting = false;
|
||||||
|
GIB_DATA(cbuf_active)->ret.available = false;
|
||||||
|
} else {
|
||||||
|
sub = Cbuf_New (&gib_interp);
|
||||||
|
GIB_DATA(sub)->type = GIB_BUFFER_PROXY;
|
||||||
|
GIB_DATA(sub)->locals = GIB_DATA(cbuf_active)->locals;
|
||||||
|
dstring_insert (sub->buf, 0, token->str+n+1, i-n-1);
|
||||||
|
if (cbuf_active->down)
|
||||||
|
Cbuf_DeleteStack (cbuf_active->down);
|
||||||
|
cbuf_active->down = sub;
|
||||||
|
sub->up = cbuf_active;
|
||||||
|
cbuf_active->state = CBUF_STATE_STACK;
|
||||||
|
GIB_DATA(cbuf_active)->ret.waiting = true;
|
||||||
|
GIB_DATA(cbuf_active)->ret.token_pos = n;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
GIB_Process_Token (struct dstring_s *token, char delim)
|
GIB_Process_Token (struct dstring_s *token, char delim)
|
||||||
{
|
{
|
||||||
if (delim != '{' && delim != '\"')
|
if (delim != '{' && delim != '\"') {
|
||||||
|
if (GIB_Process_Embedded (token))
|
||||||
|
return -1;
|
||||||
GIB_Process_Variables_All (token);
|
GIB_Process_Variables_All (token);
|
||||||
|
}
|
||||||
if (delim == '(')
|
if (delim == '(')
|
||||||
if (GIB_Process_Math (token))
|
if (GIB_Process_Math (token))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -153,7 +153,8 @@ COM_extract_line (cbuf_t *cbuf)
|
||||||
void
|
void
|
||||||
COM_parse_line (cbuf_t *cbuf)
|
COM_parse_line (cbuf_t *cbuf)
|
||||||
{
|
{
|
||||||
COM_TokenizeString (cbuf->line->str, cbuf->args);;
|
COM_TokenizeString (cbuf->line->str, cbuf->args);
|
||||||
|
dstring_clearstr (cbuf->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue