/* syntax analyser for configuration language * by Marek Zelem */ #include #include #include #include #include "log.h" #include "language.h" #include "lex.h" #include "runtime.h" #define MAX_ARGS 64 void add_fsentry(udata act, udata recursive, char *subor, udata * prog, int proglen); #ifdef CONFIG_MEDUSA_FORCE udata load_force_code(char *file); udata force_do(struct med_s *m, udata fc, var_t * arg, int n); #endif /* non-terminals */ #define S (N|0) #define P (N|1) #define P_FOR (N|2) #define PROGRAM (N|3) #define PROGRM (N|4) #define PROGELSE (N|5) #define PODM (N|6) #define PODM1 (N|7) #define PODM1M (N|8) #define PODM2 (N|9) #define PODM2M (N|10) #define PODM3 (N|11) #define BLOK (N|12) #define BLK1 (N|13) #define COND (N|14) #define PRIKAZ (N|15) #define DATA (N|16) #define HOD (N|17) #define VYRAZ (N|18) #define V1 (N|19) /* configuration language gramatics */ tab_t conflang_tab[] = { /* {status,{terminals},{rule}}, */ {S, {Lfunction, Lrecursive, Lfor, Lon, Lreturn, END}, {P, S, END}}, {S, {TEND, END}, {END}}, //P -> function (oTP) PROGRAM (oDEFUN) {P, {Lfunction, END}, {Lfunction, oTP, lID, PROGRAM, oDEFUN, END}}, ////P -> (oTP) REC (oTP) PROGRAM (oFSADD) //{P,{lFSENTRY,END},{oTP,lFSENTRY,REC,oTP,lRETAZEC,PROGRAM,oFSADD,END}}, ////REC -> (oSP1) recursive //{REC,{Lrecursive,END},{oSP1,Lrecursive,END}}, ////REC -> (oSP0) e //{REC,{END},{oSP0,END}}, //P -> oSP1 recursive P_FOR {P, {Lrecursive, END}, {oSP1, Lrecursive, P_FOR, END}}, //P -> oSP0 P_FOR {P, {Lfor, END}, {oSP0, P_FOR, END}}, //P_FOR -> Lfor (oTP) (oTP) PROGRAM (oFSADD) {P_FOR, {END}, {Lfor, oTP, lFSENTRY, oTP, lRETAZEC, PROGRAM, oFSADD, END}}, //P -> on (oTP) PROGRAM (oON) {P, {Lon, END}, {Lon, oTP, lEVENT, PROGRAM, oON, END}}, //PROGRAM -> PROGRM {PROGRAM, {END}, {PROGRM, oCRET, oS1, oS1, END}}, //PROGRM -> '{' BLOK '}' {PROGRM, {T | '{', END}, {T | '{', BLOK, T | '}', END}}, //PROGRM -> if '(' PODM ')' (oNA) (oCFALSE) (oNR) PROGRM PROGELSE {PROGRM, {Lif, END}, {Lif, T | '(', PODM, T | ')', oNA, oCFALSE, oNR, PROGRM, PROGELSE, END}}, //PROGELSE -> (oNA) (oCJUMP) (oNR) else (oNS1) PROGRM (oNS) {PROGELSE, {Lelse, END}, {oNA, oCJUMP, oNR, Lelse, oNS1, PROGRM, oNS, END}}, //PROGELSE -> (oNS) {PROGELSE, {END}, {oNS, END}}, //PROGRM -> return (oCRET) HOD ';' {PROGRM, {Lreturn, END}, {Lreturn, oCRET, HOD, T | ';', END}}, //PROGRM -> PRIKAZ ';' {PROGRM, {END}, {oPREFIX, PRIKAZ, T | ';', END}}, ////PODM -> not COND (oCNOT) //{PODM,{Lnot,END},{Lnot,COND,oCNOT,END}}, ////PODM -> '(' (oNA) PODM1 (oNS) ')' //{PODM,{T|'(',END},{T|'(',oNA,PODM1,oNS,T|')',END}}, //PODM -> COND {PODM, {END}, {oNA, PODM1, oNS, END}}, //PODM1 -> (oNA) PODM2 (oNS) PODM1M {PODM1, {END}, {oNA, PODM2, oNS, PODM1M, END}}, //PODM1M -> (oCTRUE) (oNR) or PODM1 {PODM1M, {Lor, END}, {oCTRUE, oNR, Lor, PODM1, END}}, //PODM1M -> e {PODM1M, {END}, {END}}, //PODM2 -> PODM3 PODM2M {PODM2, {END}, {PODM3, PODM2M, END}}, //PODM2M -> (oCFALSE) (oNR) and PODM2 {PODM2M, {Land, END}, {oCFALSE, oNR, Land, PODM2, END}}, //PODM2M -> e {PODM2M, {END}, {END}}, //PODM3 -> not COND (oCNOT) {PODM3, {Lnot, END}, {Lnot, COND, oCNOT, END}}, //PODM3 -> '(' (oNA) PODM1 (oNS) ')' {PODM3, {T | '(', END}, {T | '(', oNA, PODM1, oNS, T | ')', END}}, //PODM3 -> COND {PODM3, {END}, {COND, END}}, //BLOK -> PROGRM BLK1 {BLOK, {END}, {PROGRM, BLK1, END}}, //BLOK -> } {BLOK, {T | '}', END}, {T | '}', END}}, //BLK1 -> e {BLK1, {T | '}', END}, {END}}, //BLK1 -> BLOK {BLK1, {END}, {BLOK, END}}, //COND -> (oTT) (oTO) DATA {COND, {lPRIKAZ, END}, {oTT, oTO, lPRIKAZ, DATA, END}}, //COND -> (oTT) (oTO) DATA {COND, {lID, END}, {oTT, oTO, lID, DATA, END}}, //COND -> (oTT) (oTO) (oTO) HOD {COND, {lPREMENNA, END}, {oTT, oTO, lPREMENNA, oTO, lRELOP, HOD, END}}, //COND -> (oTT) (oTO) (oTO) HOD {COND, {lGLOBPREM, END}, {oTT, oTO, lGLOBPREM, oTO, lRELOP, HOD, END}}, //COND -> (oTT) VYRAZ {COND, {lCISLO, lKONSTANT, END}, {oTT, VYRAZ, END}}, //PRIKAZ -> (oTT) (oTO) (oTO) HOD {PRIKAZ, {lPREMENNA, END}, {oTT, oTO, lPREMENNA, oTO, lSETOP, HOD, END}}, //PRIKAZ -> (oTT) (oTO) (oTO) HOD {PRIKAZ, {lGLOBPREM, END}, {oTT, oTO, lGLOBPREM, oTO, lSETOP, HOD, END}}, //PRIKAZ -> (oTT) (oTO) DATA {PRIKAZ, {lPRIKAZ, END}, {oTT, oTO, lPRIKAZ, DATA, END}}, //PRIKAZ -> (oTT) (oTO) DATA {PRIKAZ, {lID, END}, {oTT, oTO, lID, DATA, END}}, #ifdef CONFIG_MEDUSA_FORCE //PRIKAZ -> (oTT) Lforce (oTP) (oFORCE) DATA {PRIKAZ, {Lforce, END}, {oTT, Lforce, oTO, lRETAZEC, oFORCE, DATA, END}}, #endif //DATA -> (oS0) e {DATA, {T | ')', T | ';', Lor, Land, END}, {oS0, END}}, //DATA -> HOD DATA {DATA, {END}, {HOD, DATA, END}}, //HOD -> (oTT) (oTO) | (oTT) (oTO) | (oTT) (oTO) {HOD, {lRETAZEC, END}, {oTT, oTO, lRETAZEC, END}}, {HOD, {lPREMENNA, END}, {oTT, oTO, lPREMENNA, END}}, {HOD, {lGLOBPREM, END}, {oTT, oTO, lGLOBPREM, END}}, //HOD -> (oS1) VYRAZ {HOD, {END}, {oS1, VYRAZ, END}}, //VYRAZ -> (oTO) V1 | (oTO) V1 {VYRAZ, {lCISLO, END}, {oTO, lCISLO, V1, END}}, {VYRAZ, {lKONSTANT, END}, {oTO, lKONSTANT, V1, END}}, //V1 -> (oTO) VYRAZ (oOP) {V1, {lOP, END}, {oTO, lOP, VYRAZ, oOP, END}}, //V1 -> e {V1, {END}, {END}}, {END} }; //HOD = (typ hodn) , ak typ==1 -> hodn je cislo //DATA = HOD HOD ... (0), ak typ je 0 potom koniec dat static void add_function(char *name, udata * prog, int proglen); #define CTT_PREFIX 0x40000000 void lex_out(lex_t * l, sym_t s) { static udata params[MAX_ARGS]; static int pos = 0; static udata prefix = 0, *prog = NULL; static int proglen = 0, progsize = 0; static struct nav_tab_s *nstack = NULL; struct nav_tab_s *nn; struct nav_rel_s *nr; #ifdef CONFIG_MEDUSA_FORCE char *ptr; #endif if (prog == NULL) { proglen = 0; progsize = 0; } if (proglen >= progsize) { progsize = proglen + 16; if ((prog = realloc(prog, progsize * sizeof(udata))) == NULL) fatal(OUTMEM); } switch (s) { case oTP: params[pos++] = l->num; break; case oSP0: params[pos++] = 0; break; case oSP1: params[pos++] = 1; break; case oTO: prog[proglen++] = l->num; break; case oTT: prog[proglen++] = (udata) (l->sym) | prefix; break; case oS0: prog[proglen++] = 0; break; case oS1: prog[proglen++] = 1; break; case oPREFIX: prefix = CTT_PREFIX; return; case oCNOT: case oCTRUE: case oCFALSE: case oCRET: case oCJUMP: prog[proglen++] = s; break; case oNA: if ((nn = malloc(sizeof(struct nav_tab_s))) == NULL) fatal(OUTMEM); nn->rel = NULL; nn->next = nstack; nstack = nn; break; case oNR: if (nstack == NULL) fatal("Chyba zasobnika navesti!!!"); if ((nr = malloc(sizeof(struct nav_rel_s))) == NULL) fatal(OUTMEM); nr->pos = proglen++; nr->next = nstack->rel; nstack->rel = nr; break; case oNS: if (nstack == NULL) fatal("Chyba zasobnika navesti!!!"); while ((nr = nstack->rel) != NULL) { prog[nr->pos] = (udata) ((long) proglen - (long) nr->pos - 1); nstack->rel = nr->next; free(nr); } nn = nstack; nstack = nn->next; free(nn); break; case oNS1: if (nstack == NULL || nstack->next == NULL) fatal("Chyba zasobnika navesti!!!"); while ((nr = nstack->next->rel) != NULL) { prog[nr->pos] = (udata) ((long) proglen - (long) nr->pos - 1); nstack->next->rel = nr->next; free(nr); } nn = nstack->next; nstack->next = nn->next; free(nn); break; case oOP: if (proglen < 3 || prog[proglen - 2] == 0) { proglen -= 2; break; } prog[proglen - 3] = ((udata(*)(udata, udata)) (prog[proglen - 2])) (prog [proglen - 3], prog [proglen - 1]); proglen -= 2; break; case oDEFUN: if (pos < 1 || params[0] == 0) { pos = 0; proglen = 0; break; } add_function((char *) (params[0]), prog, proglen); pos = 0; prog = NULL; break; case oFSADD: if (pos < 3 || params[2] == 0) { pos = 0; proglen = 0; break; } add_fsentry(params[1], params[0], (char *) (params[2]), prog, proglen); pos = 0; prog = NULL; break; case oON: if (pos < 1 || params[0] == 0) { pos = 0; proglen = 0; break; } ((void (*)(udata *, int)) (params[0])) (prog, proglen); pos = 0; prog = NULL; break; #ifdef CONFIG_MEDUSA_FORCE case oFORCE: if (proglen < 0 || prog[proglen - 1] == 0) break; ptr = (char *) (prog[proglen - 1]); if ((prog[proglen - 1] = load_force_code((char *) (prog[proglen - 1]))) == 0) { fprintf(stderr, "Invalid file %s\n", ptr); } break; #endif default: fprintf(stderr, "pos=%d - ERROR!\n", pos); } prefix = 0; return; } static struct tab_func_s { struct tab_func_s *next; char *name; udata *prog; int proglen; } *tab_func = NULL; static udata *get_funcprog(char *name) { struct tab_func_s *p = tab_func; while (p != NULL) { if (!strcmp(p->name, name)) return p->prog; p = p->next; } return NULL; } static void add_function(char *name, udata * prog, int proglen) { struct tab_func_s *new; if (get_funcprog(name) != NULL) lang_error("Redefinition of function"); if ((new = malloc(sizeof(struct tab_func_s))) == NULL) fatal(OUTMEM); new->name = name; new->prog = prog; new->proglen = proglen; new->next = tab_func; tab_func = new; } var_t *get_hodn(struct med_s *med, udata ** prog) { static var_t v; var_t *(*prem_set_get) (struct med_s *, var_t *); switch (*(*prog)++) { case 1: v.typ = VT_INT; v.d = *(*prog)++; break; case lRETAZEC: v.typ = VT_STR; v.d = *(*prog)++; break; case lPREMENNA: prem_set_get = (var_t * (*)(struct med_s *, var_t *)) (*(*prog)++); return prem_set_get(med, NULL); case lGLOBPREM: return (var_t *) (*(*prog)++); default: fatal("Invalid type of data!"); } return &v; } int runtime_error, runtime_cmd; udata exec_program(udata * prog, struct med_s *med) { udata retval, cmd, u; int cond_state; udata(*opfn) (var_t *, var_t *); var_t *v1, *v2, *vp; int n, i; var_t *(*prem_set_get) (struct med_s *, var_t *); udata(*cmdfn) (struct med_s *, var_t *, int); udata *pprg; /* !!! */ if (prog == NULL) return 0; runtime_error = 0; retval = 0; cond_state = 1; while (1) { cmd = *prog++; if (cmd & CTT_PREFIX) { runtime_cmd = 1; cmd &= ~CTT_PREFIX; } switch (cmd) { case oCNOT: cond_state = !cond_state; break; case oCTRUE: if (cond_state) prog += (long) (*prog); prog++; break; case oCFALSE: if (!cond_state) prog += (long) (*prog); prog++; break; case oCJUMP: prog += (long) (*prog); prog++; break; case oCRET: v1 = get_hodn(med, &prog); return v1->d; case lKONSTANT: case lCISLO: cond_state = ((retval = (*prog++)) != 0); break; case lGLOBPREM: v1 = (var_t *) (*prog++); opfn = (void *) (*prog++); v2 = get_hodn(med, &prog); cond_state = ((retval = opfn(v1, v2)) != 0); break; case lPREMENNA: prem_set_get = (void *) (*prog++); v1 = prem_set_get(med, NULL); opfn = (void *) (*prog++); v2 = get_hodn(med, &prog); cond_state = ((retval = opfn(v1, v2)) != 0); prem_set_get(med, v1); break; case lPRIKAZ: cmdfn = (void *) (*prog++); if ((vp = malloc(MAX_ARGS * sizeof(var_t))) == NULL) fatal(OUTMEM); pprg = prog; n = 0; while (n < MAX_ARGS) { if (*prog == 0) { prog++; break; } vp[n++] = *(get_hodn(med, &prog)); } if (n >= MAX_ARGS) { free(vp); printlog("Invalid number of arguments!\n"); while (*prog != 0) get_hodn(med, &prog); prog++; runtime_error = RT_ERR_ARGC; cond_state = 0; retval = 0; break; } cond_state = ((retval = cmdfn(med, vp, n)) != 0); i = 0; while (i < n) { /* !!! */ v1 = get_hodn(med, &pprg); *v1 = vp[i++]; } free(vp); break; #ifdef CONFIG_MEDUSA_FORCE case Lforce: if ((u = *prog++) == 0) fatal("Fatal force error!"); if ((vp = malloc(MAX_ARGS * sizeof(var_t))) == NULL) fatal(OUTMEM); pprg = prog; n = 0; while (n < MAX_ARGS) { if (*prog == 0) { prog++; break; } vp[n++] = *(get_hodn(med, &prog)); } if (n >= MAX_ARGS) { free(vp); printlog("Invalid number of arguments!\n"); while (*prog != 0) get_hodn(med, &prog); prog++; runtime_error = RT_ERR_ARGC; cond_state = 0; retval = 0; break; } cond_state = ((force_do(med, u, vp, n)) != 0); i = 0; while (i < n) { /* !!! */ v1 = get_hodn(med, &pprg); *v1 = vp[i++]; } free(vp); break; #endif case lID: u = *prog++; while (*prog != 0) get_hodn(med, &prog); prog++; cond_state = ((retval = exec_program(get_funcprog ((char *) u), med) ) != 0); break; default: fatal("Illegal instruction"); } if (runtime_error) { printlog("Runtime error %d\n", runtime_error); /* or execute: on error !!! */ return 0; } } } int read_config(char *subor) { int fd; sym_t r; if ((fd = open(subor, O_RDONLY)) < 0) fatal("Can't open config file!"); lex_line = 1; lex_char = 0; r = sa_automat(conflang_tab, S, getlex, lex_out, fd); if (lang_errors != 0 || r != 0) fatal("Error(s) in config file!"); return 0; }