static void rcc_pushstr(REgg *egg, char *str, int filter) { int dotrim = 1; int i, j, len; REggEmit *e = egg->remit; e->comment (egg, "encode %s string (%s) (%s)", filter? "filtered": "unfiltered", str, callname); if (filter) for (i=0; str[i]; i++) { if (str[i]=='\\') { switch (str[i+1]) { case 't': str[i]='\t'; break; case 'n': str[i]='\n'; break; case 'e': str[i]='\x1b'; break; default: dotrim = 0; break; } if (dotrim) memmove (str+i+1, str+i+2, strlen (str+i+2)); } } len = strlen (str); j = (len-len%e->size)+e->size; e->set_string (egg, dstvar, str, j); free (dstvar); dstvar = NULL; }
static void rcc_element(REgg *egg, char *str) { REggEmit *e = egg->remit; char *p = strrchr (str, ','); int num, num2; if (CTX) { nargs = 0; if (mode == GOTO) mode = NORMAL; // XXX while (p) { *p = '\0'; p = (char *)skipspaces (p+1); rcc_pusharg (egg, p); p = strrchr (str, ','); } if (callname) rcc_pusharg (egg, str); else if (mode == NORMAL) { if (!atoi (str)) { if (dstvar == NULL) /* return string */ dstvar = strdup (".fix0"); rcc_pushstr (egg, str, 1); } } } else { switch (mode) { case ALIAS: e->equ (egg, dstvar, str); R_FREE (dstvar); mode = NORMAL; break; case SYSCALL: syscalls[nsyscalls].name = strdup (dstvar); syscalls[nsyscalls].arg = strdup (str); nsyscalls++; R_FREE (dstvar); break; case GOTO: elem[elem_n] = 0; e->jmp (egg, elem, 0); break; default: p = strchr (str, ','); if (p) { *p='\0'; num2 = atoi (p+1); } else num2 = 0; num = atoi (str) + num2; stackframe = num; stackfixed = num2; if (mode != NAKED) e->frame (egg, stackframe+stackfixed); } elem[0] = 0; elem_n = 0; } }
static void rcc_pusharg(REgg *egg, char *str) { REggEmit *e = egg->emit; char buf[64], *p = r_egg_mkvar (egg, buf, str, 0); if (!p) return; // TODO: free (ctxpush[context]); ctxpush[context] = strdup (p); // INDEX IT WITH NARGS OR CONTEXT?!? nargs++; if (pushargs) e->push_arg (egg, varxs, nargs, p); //ctxpush[context+nbrackets] = strdup(str); // use nargs??? (in callname) }
R_API int r_egg_lang_parsechar(REgg *egg, char c) { REggEmit *e = egg->remit; char *ptr, str[64], *tmp_ptr = NULL; if (c=='\n') { line++; elem_n = 0; } //eprintf ("CH %c\n", c); /* comments */ if (skipline) { if (c != '\n') { oc = c; return 0; } skipline = 0; } if (mode == DATA) return parsedatachar (egg, c); if (mode == INLINE) return parseinlinechar (egg, c); /* quotes */ if (quoteline) { if (c != quoteline) { if (quotelinevar == 1) { if (c == '`') { elem[elem_n] = 0; elem_n = 0; tmp_ptr = r_egg_mkvar (egg, str, elem, 0); r_egg_printf (egg, "%s", tmp_ptr); free (tmp_ptr); quotelinevar = 0; } else elem[elem_n++] = c; } else { if (c == '`') { elem_n = 0; quotelinevar = 1; } else r_egg_printf (egg, "%c", c); } oc = c; return 0; } else { r_egg_printf (egg, "\n"); quoteline = 0; } } if (commentmode) { if (c=='/' && oc == '*') commentmode = 0; oc = c; return 0; } else if (c=='*' && oc == '/') commentmode = 1; if (slurp) { if (slurp != '"' && c == slurpin) exit (eprintf ( "%s:%d Nesting of expressions not yet supported\n", file, line)); if (c == slurp && oc != '\\') { slurp = 0; elem[elem_n] = '\0'; if (elem_n > 0) rcc_element (egg, elem); else e->frame (egg, 0); elem_n = 0; } else elem[elem_n++] = c; elem[elem_n] = '\0'; } else { switch (c) { case ';': rcc_next (egg); break; case '"': slurp = '"'; break; case '(': slurpin = '('; slurp = ')'; break; case '{': if (CTX>0) { // r_egg_printf (egg, " %s:\n", get_frame_label (0)); r_egg_printf (egg, " __begin_%d_%d_%d:\n", nfunctions, CTX, nestedi[CTX]); //%s:\n", get_frame_label (0)); } rcc_context (egg, 1); break; case '}': endframe = nested[CTX-1]; if (endframe) { // XXX: use endframe[context] r_egg_printf (egg, "%s\n", endframe); // R_FREE (endframe); } if (CTX>0) { if (nestede[CTX]) { r_egg_printf (egg, "%s:\n", nestede[CTX]); //nestede[CTX] = NULL; } else { r_egg_printf (egg, " __end_%d_%d_%d:\n", nfunctions, CTX, nestedi[CTX-1]); //get_end_frame_label (egg)); } nbrackets++; } rcc_context (egg, -1); if (CTX== 0) { nbrackets = 0; nfunctions++; } break; case ':': if (oc == '\n' || oc == '}') quoteline = '\n'; else elem[elem_n++] = c; break; case '#': if (oc == '\n') skipline = 1; break; case '/': if (oc == '/') skipline = 1; else elem[elem_n++] = c; break; default: elem[elem_n++] = c; } if (slurp) { if (elem_n) { ptr = elem; elem[elem_n] = '\0'; while (is_space (*ptr)) ptr++; rcc_fun (egg, ptr); } elem_n = 0; } } if (c!='\t' && c!=' ') oc = c; return 0; }
/* TODO: split this function into several ones..quite long fun */ static void rcc_next(REgg *egg) { const char *ocn; REggEmit *e = egg->remit; char *str = NULL, *p, *ptr, buf[64]; int i; if (setenviron) { elem[elem_n - 1] = 0; r_sys_setenv (setenviron, elem); R_FREE (setenviron); return; } if (includefile) { char *p, *q, *path; // TODO: add support for directories elem[elem_n-1] = 0; path = find_include (elem, includefile); if (!path) { eprintf ("Cannot find include file '%s'\n", elem); return; } free (includefile); includefile = NULL; rcc_reset_callname (); p = q = r_file_slurp (path, NULL); if (p) { int oline = ++line; elem[0] = 0; // TODO: this must be a separate function elem_n = 0; line = 0; for (; *p; p++) r_egg_lang_parsechar (egg, *p); free (q); line = oline; } else { eprintf ("Cannot find '%s'\n", path); } free (path); return; } docall = 1; if (callname) { if (!strcmp (callname, "goto")) { if (nargs != 1) { eprintf ("Invalid number of arguments for goto()\n"); return; } e->jmp (egg, ctxpush[CTX], 0); rcc_reset_callname (); return; } if (!strcmp (callname, "break")) { e->trap (egg); rcc_reset_callname (); return; } ptr = strchr (callname, '='); if (ptr) { *ptr = '\0'; //ocn = ptr+1; // what is the point of this? } ocn = skipspaces (callname); if (!ocn) return; str = r_egg_mkvar (egg, buf, ocn, 0); if (!str) { eprintf ("Cannot mkvar\n"); return; } if (*ocn=='.') e->call (egg, str, 1); if (!strcmp (str, "while")) { char var[128]; if (lastctxdelta >= 0) exit (eprintf ("ERROR: Unsupported while syntax\n")); sprintf (var, "__begin_%d_%d_%d\n", nfunctions, CTX, nestedi[CTX-1]); e->while_end (egg, var); //get_frame_label (1)); #if 0 eprintf ("------------------------------------------ lastctx: %d\n", lastctxdelta); // TODO: the pushvar is required for the if(){}while(); constructions //char *pushvar = ctxpush[context+nbrackets-1]; /* TODO: support to compare more than one expression (LOGICAL OR) */ rcc_printf (" pop %%eax\n"); rcc_printf (" cmp $0, %%eax\n"); // XXX MUST SUPPORT != 0 COMPARE HERE /* TODO : Simplify!! */ //if (pushvar) // printf(" push %s /* wihle push */\n", pushvar); if (lastctxdelta<0) rcc_printf (" jnz %s\n", get_frame_label (1)); else rcc_printf (" jnz %s\n", get_frame_label (0)); //if (pushvar) // printf(" pop %%"R_AX" /* while pop */\n"); #endif nargs = 0; } else { for (i = 0; i < nsyscalls; i++) { if (!strcmp (str, syscalls[i].name)) { p = syscallbody; e->comment (egg, "set syscall args"); e->syscall_args (egg, nargs); docall = 0; e->comment (egg, "syscall"); r_egg_lang_parsechar (egg, '\n'); /* FIX parsing issue */ if (p) { for (; *p; p++) r_egg_lang_parsechar (egg, *p); } else { char *q, *s = e->syscall (egg, nargs); if (s) { for (q=s; *q; q++) r_egg_lang_parsechar (egg, *q); free (s); } else eprintf ("Cannot get @syscall payload\n"); } docall = 0; break; } } if (docall) for (i = 0; i < ninlines; i++) { if (!strcmp (str, inlines[i].name)) { p = inlines[i].body; docall = 0; e->comment (egg, "inline"); r_egg_lang_parsechar (egg, '\n'); /* FIX parsing issue */ for (; *p; p++) r_egg_lang_parsechar (egg, *p); docall = 0; break; } } if (docall) { e->comment (egg, "call in mode %d", mode); e->call (egg, str, 0); } } if (nargs > 0) e->restore_stack (egg, nargs*e->size); if (ocn) { // Used to call .var0() /* XXX: Probably buggy and wrong */ *buf = 0; free (str); str = r_egg_mkvar (egg, buf, ocn, 0); if (*buf) e->get_result (egg, buf); //else { eprintf("external symbol %s\n", ocn); } } /* store result of call */ if (dstvar) { if (mode != NAKED) { *buf = 0; free (str); str = r_egg_mkvar (egg, buf, dstvar, 0); if (*buf == 0) eprintf ("Cannot resolve variable '%s'\n", dstvar); else e->get_result (egg, buf); } R_FREE (dstvar); } rcc_reset_callname (); } else { int vs = 'l'; char type, *eq, *ptr = elem; elem[elem_n] = '\0'; ptr = (char*)skipspaces (ptr); if (*ptr) { eq = strchr (ptr, '='); if (eq) { char str2[64], *p, ch = *(eq-1); *eq = '\0'; eq = (char*) skipspaces (eq+1); p = r_egg_mkvar (egg, str2, ptr, 0); vs = varsize; if (is_var (eq)) { eq = r_egg_mkvar (egg, buf, eq, 0); if (varxs=='*') e->load (egg, eq, varsize); else /* XXX this is a hack .. must be integrated with pusharg */ if (varxs=='&') e->load_ptr (egg, eq); if (eq) { free (eq); eq = NULL; } type = ' '; } else type = '$'; vs = 'l'; // XXX: add support for != 'l' size e->mathop (egg, ch, vs, type, eq, p); free(p); } else { if (!strcmp (ptr, "break")) { // handle 'break;' e->trap (egg); rcc_reset_callname (); } else { e->mathop (egg, '=', vs, '$', ptr, NULL); } } } } free (str); }
static void rcc_context(REgg *egg, int delta) { REggEmit *emit = egg->remit; char str[64]; if (CTX>31 || CTX <0) return; nestedi[CTX]++; if (callname && CTX>0) {// && delta>0) { // set_nested (callname); //eprintf (" - - - - - - - set nested d=%d c=%d (%s)\n", delta, context-1, callname); //shownested(); } CTX += delta; lastctxdelta = delta; if (CTX == 0 && delta < 0) { if (mode != NAKED) emit->frame_end (egg, stackframe+stackfixed, nbrackets); if (mode == NORMAL) /* XXX : commenting this makes hello.r unhappy! TODO: find a cleaner alternative */ stackframe = 0; mode = NORMAL; } else { /* conditional block */ //eprintf ("Callname is (%s)\n", callname); const char *elm = skipspaces (elem); const char *cn = callname; //if (nested[context-1]) #if 0 if (delta<0 && context>0) { eprintf ("close bracket foo!!!\n"); shownested (); cn = strdup (nested[context-1]); eprintf ("STATEMENT cn=(%s) idx=%d (%s)\n", cn, context-1, nested[context-1]); eprintf ("CNTXXXPUSH (%s)\n", ctxpush[context-1]); #if 0 if (!strcmp (cn, "while")) { emit->while_end (egg, get_frame_label (context-1)); //char *var = get_frame_label (0); //emit->jmp (egg, var, 0); return; } #endif } #endif //eprintf ("ELEM (%s)\n", elm); //eprintf ("END BLOCK %d, (%s)\n", context, nested[context-1]); //eprintf ("CN = (%s) %d (%s) delta=%d\n", cn, context, nested[context-1], delta); if (cn) { //if (callname) { // handle 'foo() {' /* TODO: this must be an array */ char *b, *g, *e, *n; emit->comment (egg, "cond frame %s (%s)", cn, elm); /* TODO: simplify with a single for */ b = strchr (elem, '<'); /* below */ g = strchr (elem, '>'); /* greater */ e = strchr (elem, '='); /* equal */ n = strchr (elem, '!'); /* negate */ if (!strcmp (cn, "while")) { char lab[128]; sprintf (lab, "__begin_%d_%d_%d", nfunctions, CTX-1, nestedi[CTX-1]); emit->get_while_end (egg, str, ctxpush[CTX-1], lab); //get_frame_label (2)); //get_frame_label (2)); //eprintf ("------ (%s)\n", ctxpush[context-1]); // free (endframe); // XXX: endframe is deprecated, must use set_nested only if (delta>0) { set_nested (egg, str); } rcc_set_callname ("if"); // append 'if' body } if (!strcmp (cn, "if")) { //emit->branch (egg, b, g, e, n, varsize, get_end_frame_label (egg)); // HACK HACK :D sprintf (str, "__end_%d_%d_%d", nfunctions, CTX-1, nestedi[CTX-1]); nestede[CTX-1] = strdup (str); sprintf (str, "__end_%d_%d_%d", nfunctions, CTX, nestedi[CTX-1]); emit->branch (egg, b, g, e, n, varsize, str); if (CTX>0) { /* XXX .. */ } rcc_reset_callname (); } //else eprintf ("Unknown statement (%s)(%s)\n", cn, elem); } // handle '{ ..' } }
static void rcc_fun(REgg *egg, const char *str) { char *ptr, *ptr2; REggEmit *e = egg->remit; str = skipspaces (str); if (CTX) { ptr = strchr (str, '='); if (ptr) { *ptr++ = '\0'; free (dstvar); dstvar = strdup (skipspaces (str)); ptr2 = (char *)skipspaces (ptr); if (*ptr2) rcc_set_callname (skipspaces (ptr)); } else { str = skipspaces (str); rcc_set_callname (skipspaces (str)); egg->remit->comment (egg, "rcc_fun %d (%s)", CTX, callname); } } else { ptr = strchr (str, '@'); if (ptr) { *ptr++ = '\0'; mode = NORMAL; if (strstr (ptr, "env")) { //eprintf ("SETENV (%s)\n", str); free (setenviron); setenviron = strdup (skipspaces (str)); slurp = 0; } else if (strstr (ptr, "fastcall")) { /* TODO : not yet implemented */ } else if (strstr (ptr, "syscall")) { if (*str) { mode = SYSCALL; dstvar = strdup (skipspaces (str)); } else { mode = INLINE; free (syscallbody); syscallbody = malloc (4096); // XXX hardcoded size dstval = syscallbody; R_FREE (dstvar); ndstval = 0; *syscallbody = '\0'; } } else if (strstr (ptr, "include")) { free (includefile); includefile = strdup (skipspaces (str)); slurp = 0; } else if (strstr (ptr, "alias")) { mode = ALIAS; dstvar = strdup (skipspaces (str)); } else if (strstr (ptr, "data")) { mode = DATA; ndstval = 0; dstvar = strdup (skipspaces (str)); dstval = malloc (4096); } else if (strstr (ptr, "naked")) { mode = NAKED; free (dstvar); dstvar = strdup (skipspaces (str)); dstval = malloc (4096); ndstval = 0; r_egg_printf (egg, "%s:\n", str); } else if (strstr (ptr, "inline")) { mode = INLINE; free (dstvar); dstvar = strdup (skipspaces (str)); dstval = malloc (4096); ndstval = 0; } else { // naked label if (*ptr) r_egg_printf (egg, "\n.%s %s\n", ptr, str); r_egg_printf (egg, "%s:\n", str); } } else { //e->jmp (egg, ctxpush[context], 0); if (CTX>0) { // WTF? eprintf ("LABEL %d\n", CTX); r_egg_printf (egg, "\n%s:\n", str); } else { if (!strcmp (str, "goto")) { mode = GOTO; } else { // call() // or maybe jmp? e->call (egg, str, 0); } } } } }
R_API char *r_egg_mkvar(REgg *egg, char *out, const char *_str, int delta) { int i, idx, len, qi; char *oldstr = NULL, *str = NULL, foo[32], *q, *ret = NULL; delta += stackfixed; // XXX can be problematic if (!_str) return NULL; /* fix segfault, but not badparsing */ /* XXX memory leak */ ret = str = oldstr = strdup (skipspaces (_str)); //if (num || str[0]=='0') { sprintf(out, "$%d", num); ret = out; } if ( (q = strchr (str, ':')) ) { *q = '\0'; qi = atoi (q+1); varsize = (qi==1)? 'b': 'l'; } else varsize='l'; if (*str == '*' || *str == '&') { varxs = *str; str++; } else varxs = 0; if (str[0] == '.') { REggEmit *e = egg->remit; idx = atoi (str+4) + delta + e->size; if (!strncmp (str+1, "ret", 3)) { strcpy (out, e->retvar); } else if (!strncmp (str+1, "fix", 3)) { e->get_var (egg, 0, out, idx-stackfixed); //sprintf(out, "%d(%%"R_BP")", -(atoi(str+4)+delta+R_SZ-stackfixed)); } else if (!strncmp (str+1, "var", 3)) { e->get_var (egg, 0, out, idx); //sprintf(out, "%d(%%"R_BP")", -(atoi(str+4)+delta+R_SZ)); } else if (!strncmp (str+1, "arg", 3)) { if (str[4]) { if (stackframe == 0) { e->get_var (egg, 1, out, 4); //idx-4); } else { e->get_var (egg, 2, out, idx+4); } } else { /* TODO: return size of syscall */ if (callname) { for (i=0; i<nsyscalls; i++) if (!strcmp (syscalls[i].name, callname)) { free (oldstr); return strdup(syscalls[i].arg); } eprintf ("Unknown arg for syscall '%s'\n", callname); } else eprintf ("NO CALLNAME '%s'\n", callname); } } else if (!strncmp (str+1, "reg", 3)) { // XXX: can overflow if out is small if (attsyntax) snprintf (out, 32, "%%%s", e->regs (egg, atoi (str+4))); else snprintf (out, 32, "%s", e->regs (egg, atoi (str+4))); } else { out = str; /* TODO: show error, invalid var name? */ eprintf ("Something is really wrong\n"); } ret = strdup(out); free (oldstr); } else if (*str=='"' || *str=='\'') { int mustfilter = *str=='"'; /* TODO: check for room in stackfixed area */ str++; len = strlen (str)-1; if (!stackfixed || stackfixed <len) eprintf ("WARNING: No room in the static stackframe! (%d must be %d)\n", stackfixed, len); str[len]='\0'; snprintf (foo, sizeof (foo)-1, ".fix%d", nargs*16); /* XXX FIX DELTA !!!1 */ free(dstvar); dstvar = strdup (skipspaces (foo)); rcc_pushstr (egg, str, mustfilter); ret = r_egg_mkvar (egg, out, foo, 0); free (oldstr); } return ret; }