/* Ok, simple (hopefully) recursive descent parser. */
#include <creator.h>
#include <parser.h>
int pos, force_string;
mixed func;
protected void create() {
seteuid("Root");
}
mixed *parse_args(string str, string close) {
mixed *args, *m, *m2;
object *obs;
string s1, s2, s3, s4, s5, s6, s7;
int i;
mapping map;
args = ({ });
while (strlen(str)) {
while (strlen(str) && str[0] == ' ') str = str[1..<1];
if (!strlen(str) || str[0..0] == close) return ({ args, str[1..<1] });
switch (str[0]) {
case '\'' :
if (sscanf(str, "'%s'%s", s1, s2) != 2) {
printf("Unterminated string.\n");
return 0;
}
args += ({ replace_string(s1, "\\n", "\n") });
str = s2;
break;
case '`' :
if (sscanf(str, "`%s`%s", s1, s2) != 2) {
printf("Unterminated string.\n");
return 0;
}
args += ({ replace_string(s1, "\\n", "\n") });
str = s2;
break;
case '"' :
if (sscanf(str, "\"%s\"%s", s1, s2) != 2) {
printf("Unterminated string.\n");
return 0;
}
args += ({ replace_string(s1, "\\n", "\n") });
str = s2;
break;
case '{' :
m = parse_args(str[1..<1], "}");
if (!m) {
return 0;
}
args += ({ m[0] });
str = m[1];
break;
case '[' :
/* put here to catch a mudfreezing bug */
if (sscanf(str[1..<1], "%s]%s", s1, s2) != 2) {
printf("Unmatched [.\n");
return 0;
}
str = str[1..<1];
map = ([ ]);
while (1) {
m = parse_args(str, ":");
/* Ok... if we cannot find another : maybe we are at the end? */
if (!m) {
while (strlen(str) && str[0] == ' ') {
str = str[1..<1];
}
if (str[0] == ']') {
break;
}
}
if (!(m2 = parse_args(str, ","))) {
if (!(m2 = parse_args(str, "]"))) {
return 0;
}
if (sizeof(m[0])) {
map[m[0][0]] = (sizeof(m2[0])?m2[0][0]:0);
}
break;
}
if (sizeof(m[0])) {
map[m[0][0]] = (sizeof(m2[0])?m2[0][0]:0);
}
}
args += ({ map });
break;
case '|' :
if (sscanf(str, "|%s|%s", s1, s2) != 2) {
printf("Unmatched |\n");
return 0;
}
obs = WIZ_PRESENT->wiz_present(str, this_player());
if (!sizeof(obs)) {
args += ({ this_player() });
} else if (sizeof(obs) == 1) {
args += ({ obs[0] });
} else {
args += ({ obs });
}
str = s2;
break;
case '0'..'9' :
case '-' :
if (sscanf(str, "%d%s", i, str) != 2) {
printf("Number expected.\n");
return 0;
}
args += ({ i });
break;
default :
s2 = s3 = 0;
sscanf(str, "%s,%s", s4, s2);
sscanf(str, "%s"+close+"%s", s5, s3);
if (sscanf(str, "%s->%s", s6, s7) == 2 &&
(!s3 || strlen(s5) > strlen(s6)) &&
(!s2 || strlen(s4) > strlen(s6))) {
/* Now we do something truely revolting.... */
while (s7[0] == ' ') s7 = s7[1..<1];
if (sscanf(s7, "%s(%s", s1, s7) != 2) {
printf("'(' expected.\nLine left unprocessed %s\n", s7);
return 0;
}
obs = WIZ_PRESENT->wiz_present(s6, this_player());
if (!sizeof(obs)) {
printf("The object %s needs to exist.\n", s6);
return 0;
}
m = parse_args(s7, ")");
if (!m) {
return 0;
}
if (sizeof(m[0]) < 6) {
m[0] += allocate(6-sizeof(m[0]));
}
obs = map_array(obs, "mapped_call", this_object(), s1, m[0]);
if (sizeof(obs) == 1) {
args += obs;
} else {
args += ({ obs });
}
str = m[1];
break;
} else if (s2 && s3)
if (strlen(s4) < strlen(s5)) {
s1 = ",";
str = s4;
} else {
s1 = close;
s2 = s3;
str = s5;
} else if (s2) {
s1 = ",";
str = s4;
} else if (s3) {
s1 = close;
s2 = s3;
str = s5;
} else {
s1 = "";
s2 = "";
}
obs = WIZ_PRESENT->wiz_present(str, this_player());
if (!sizeof(obs)) {
if (str[0] >= '0' && str[0] <= '9' || str[0] == '-') {
sscanf(str, "%d%s", i, str);
args += ({ i });
} else
args += ({ replace_string(str, "\\n", "\n") });
} else if (sizeof(obs) == 1)
args += ({ obs[0] });
else
args += ({ obs });
str = s1+s2;
break;
}
/* Skip rubbish and if we dont have a comma we have finished. */
while (strlen(str) && str[0] == ' ') {
str = str[1..<1];
}
if (!strlen(str)) {
return ({ args, str });
}
if (str[0..0] == close) {
return ({ args, str[1..<1] });
}
if (str[0] != ',') {
printf("Parse error reading arguments, ',' or '%s' expected.\n", close);
printf("Line left unprocessed %s\n", str);
return 0;
}
str = str[1..<1];
}
return ({ args, str });
} /* parse_args() */
#ifdef NOPE
void inform_of_call(object ob, mixed *argv) {
string str;
int i;
str = this_object()->query_cap_name() + " calls " + argv[0] + "(";
for (i=1; i<sizeof(argv); ) {
str += replace(sprintf("%O", argv[i]), "\n", " ");
if (++i < sizeof(argv)) str += ",";
}
/* Arggghhh! This is annoying me.
* Same comment here.
ob->event_inform(this_object(), str + ") on you", "call");
*/
} /* inform_of_call() */
#endif
protected mixed mapped_call(object ob, string func, mixed *argv) {
/* inform_of_call(ob, argv); */
return call_other(ob, func, argv ...);
} /* mapped_call() */
/* Free form parse_args code */
protected int parse_frogs(string str) {
mixed junk;
/* We are not as such looking for an end thingy of any sort... */
junk = parse_args(str, ";");
/* It has already printed an error, so we return 1... */
if (!junk)
return 1;
write("The line "+str+" returns: \n");
printf("%O\n", junk[0]);
return 1;
} /* parse_frogs() */
/* Ok, simple (hopefully) recursive descent parser. */
mixed expr();
protected mixed bit4() {
mixed val1, val2, val3;
if (pos < sizeof(func)) {
if (pointerp(func[pos])) {
return func[pos++][0];
}
if (stringp(func[pos])) {
if (func[pos][0] == '$') {
/* We want a variable... */
val1 = (object)this_player()->get_obvar(func[pos][1..<1]);
pos++;
return val1;
}
if (force_string) {
force_string = 0;
return func[pos++];
}
val1 = (object *)WIZ_PRESENT->wiz_present(func[pos], this_player());
if (!sizeof(val1)) {
return func[pos++];
}
pos++;
if (sizeof(val1) == 1) {
return val1[0];
}
return val1;
}
switch (func[pos]) {
case TOK_OBRAC :
pos++;
val1 = expr();
if (func[pos] != TOK_CBRAC) {
printf("Mismatched brackets.\n");
} else {
pos++;
}
break;
case TOK_SARRAY :
pos++;
val1 = ({ });
while (pos < sizeof(func) &&
func[pos] != TOK_EARRAY) {
if (func[pos] == TOK_COMMA) {
pos++;
}
val2 = expr();
if (func[pos] != TOK_COMMA &&
func[pos] != TOK_EARRAY) {
printf("Error processing array.\n");
return 0;
}
val1 += ({ val2 });
}
pos++;
break;
case TOK_SMAPPING :
pos++;
val1 = ([ ]);
while (pos < sizeof(func) && func[pos] != TOK_EMAPPING) {
if (func[pos] == TOK_COMMA) pos++;
val2 = expr();
if (func[pos] != TOK_COLON) {
printf("Error processing mapping, expected :.\n");
return 0;
}
pos++;
val3 = expr();
if (func[pos] != TOK_EMAPPING && func[pos] != TOK_COMMA) {
printf("Error processing mapping, expected , or ].\n");
return 0;
}
val1[val2] = val3;
}
printf("End of mapping.\n");
pos++;
break;
default :
/* Anything else is a potential object. */
printf("Broken parser....\n");
break;
}
}
return val1;
} /* bit4() */
protected mixed do_function_call(object ob, string name, mixed stuff) {
string found;
object shad;
if (objectp(ob)) {
shad = ob;
while ((shad = shadow(shad, 0))) {
if ((found = function_exists(name, ob)))
break;
}
if (!found && !(found = function_exists(name, ob))) {
printf("*** function %s not found in %s ***\n",
name, file_name(ob));
return 0;
} else {
printf("*** function %s on %s found in %s ***\n", name, file_name(ob),
found);
}
if ((ob != this_player()) && ob->query_property("player") &&
!ob->query_property("no score")) {
unguarded((: write_file,
(DOMAIN_H->query_member("liaison",TP->query_name()) ?
"/d/admin/log/CALL_LIAISONS.log" :
"/d/admin/log/CALL_CREATORS.log" ),
sprintf("%s: %s (%O) called %s(%s) on %s (%O)\n",
ctime(time()),
this_player()->query_name(), this_player(),
name,
implode(stuff - ({0}), ", "), ob->query_name(),
ob) :));
user_event( this_object(), "inform",
sprintf("%s called %s(%s) on %s",
this_player()->query_name(), name, implode(stuff - ({0}), ", "),
ob->query_name()), "calls");
}
return call_other(ob, name, stuff[0], stuff[1], stuff[2],
stuff[3], stuff[4], stuff[5]);
}
return 0;
} /* do_function_call() */
protected mixed bit3() {
mixed *tmp, val1, val2, val3;
int i;
val1 = bit4();
while (pos < sizeof(func)) {
switch (func[pos]) {
case TOK_CALL :
pos++;
force_string = 1;
val2 = bit4();
force_string = 0;
if (func[pos] != TOK_OBRAC) {
printf("Open bracket expected.\n");
} else {
tmp = ({ });
pos++;
while (pos < sizeof(func) && func[pos] != TOK_CBRAC) {
if (func[pos] == TOK_COMMA) pos++;
val3 = expr();
if (func[pos] != TOK_COMMA && func[pos] != TOK_CBRAC) {
printf("Error in function arguments.\n");
return 0;
}
tmp += ({ val3 });
}
pos++;
}
if (objectp(val1)) {
val1 = ({ val1 });
}
if (!pointerp(val1)) {
printf("Array or object expected for function call.\n");
break;
}
if (!stringp(val2)) {
printf("String expected for the function call name.\n");
break;
}
if (sizeof(tmp) < 6) {
tmp += allocate(6-sizeof(tmp));
}
for (i=0;i<sizeof(val1);i++) {
val1[i] = do_function_call(val1[i], val2, tmp);
}
if (sizeof(val1) == 1) {
val1 = val1[0];
}
break;
case TOK_SMAPPING :
/* Array/mapping index... */
pos++;
val2 = expr();
if (func[pos] == TOK_DOTDOT) {
pos++;
val3 = expr();
if (func[pos] != TOK_EMAPPING) {
printf("Expected closeing ].\n");
break;
}
pos++;
if (!pointerp(val1)) {
printf("Can only use the .. syntax on arrays.\n");
break;
}
if (!intp(val2) || !intp(val3)) {
printf("Indexes must be integers.\n");
break;
}
val1 = val1[val2..val3];
break;
}
if (func[pos] != TOK_EMAPPING) {
printf("Expected closeing ].\n");
break;
}
pos++;
if (mappingp(val1)) {
/* Anything is a legal index... */
val1 = val1[val2];
} else if (pointerp(val1)) {
/* Only integers... */
if (!intp(val2)) {
printf("Can only use integers as an index on an array.\n");
} else if (val2 < 0 || val2 >= sizeof(val1)) {
printf("Index out of bounds.\n");
} else {
val1 = val1[val2];
}
} else {
printf("Can only index off arrays or mappings.\n");
}
break;
default :
return val1;
}
}
return val1;
} /* bit3() */
protected mixed bit2() {
mixed val1, val2;
val1 = bit3();
while (pos < sizeof(func)) {
switch (func[pos]) {
case TOK_MULT :
pos ++;
val2 = bit3();
if ((!intp(val1) && !floatp(val1)) || (!intp(val2) && !floatp(val2))) {
printf("Incompatible types in multiply, both must be integers.\n");
val1 = 0;
} else {
val1 = val1*val2;
}
break;
case TOK_DIV :
pos ++;
val2 = bit3();
if ((!intp(val1) && !floatp(val1)) || (!intp(val2) && !floatp(val2))) {
printf("Incompatible types in division, both must be integers.\n");
val1 = 0;
} else if (!val2) {
printf("Division by 0 error.\n");
} else {
val1 = val1/val2;
}
break;
default :
return val1;
}
}
return val1;
} /* bit2() */
mixed expr() {
mixed val1, val2;
val1 = bit2();
while (pos < sizeof(func)) {
switch (func[pos]) {
case TOK_PLUS :
pos ++;
val2 = bit2();
if (pointerp(val1) && !pointerp(val2)) {
printf("Incompatible types in addition, array and something "
"else.\n");
val1 = 0;
} else {
val1 = val1 + val2;
}
break;
case TOK_MINUS :
pos ++;
val2 = bit2();
if (pointerp(val1) && !pointerp(val2)) {
printf("Incompatible types in addition, array and something "
"else.\n");
val1 = 0;
} else {
val1 = val1 + val2;
}
break;
case TOK_ASSIGN :
pos++;
val2 = expr();
if (pointerp(val1) || mappingp(val1)) {
printf("Cannot use an array or mapping as a variable name.\n");
} else {
this_player()->set_obvar(val1, val2);
}
val1 = val2;
break;
default :
return val1;
}
}
return val1;
} /* expr() */
void init_expr(string expr) {
pos = 0;
force_string = 0;
func = TOKENISER->tokenise(expr);
}
void finish_expr() {
func = 0;
}
#ifdef BOOLEAN
/*
* Actually. I think I am starting to get carried away here. So, I will
* stop...
*/
mixed eval() {
mixed *tmp, val1, val2;
int i, j;
val1 = bit2();
while (pos < sizeof(func))
switch(func[pos]) {
case TOK_EQUAL :
case TOK_GREATOR :
case TOK_LESS :
case TOK_GREATOREQ :
case TOK_LESSEQ :
}
} /* eval() */
#endif