// Keyword Interpreter Code Generator // // by Nikolai Golovchenko March 31, 2000 - April 2, 2000 // http://techref.massmind.org/member/NG--944 // golovchenko@mail.ru #include "keyword.h" #include "keyword.inc" bool Insense = 0, Whole = 0; //options //----------- Debug ------------------ //Keywords=send%0D%0Awrite%0D%0Aread%0D%0Aon%0D%0Aoff%0D%0A0%0D%0A1%0D%0Ahelp%0D%0Atest%0D%0AgetEE%0D%0AputEE%0D%0A //Keywords=writeROM%0D%0AwriteRAM%0D%0A //Keywords=offset%0D%0Aecho%0D%0Aon%0D%0Aoff%0D%0A%0D%0A //--------------- LISTNODE class ------------------------------------------ listnode :: listnode (char v) { keyword = 0; nextchar = 0; altchar = 0; val = v; state = 0; passes = 0; reserved = 0; } void listnode :: setkeycode(int code) { this->keyword = code; } //----------------- LISTTREE class ---------------------------------------- listtree :: listtree(bool insens, bool whole) { ListIndex = 0; //points to the next element Start = 0; nextstate = 1; keywords = 0; insensitive = insens; wholeword = whole; searchindex = 0; searchnextindex = 0; Error = 0; } listtree :: ~listtree() { //free memory while(--ListIndex >= 0) { delete List[ListIndex]; } } char *listtree :: addkeyword(char *t) { listnode *ptr, *cpy; cpy = ptr = Start; int state = 0; //initial state (for the first character) keywords++; //keywords codes start from 1 do { //add one character to the tree if(state != 0) { //next character if(ptr->nextchar != 0) { ptr = ptr->nextchar; } else { ptr = ptr->nextchar = new listnode('\0'); List[ListIndex++] = ptr; //put it in linear list } } //scan if the character already there while(ptr != NULL) { cpy = ptr; if((ptr->val == *t) || (ptr->val == '\0')) { //found equal or empty in alternatives list ptr->passes++; if(ptr->reserved != 0) { if(isspace(*(t+1)) || (*(t+1) == '\0')) { Error = 5; //two same keywords } else { //matched, but this is the end of some keyword //compensate for reserved state state = ptr->reserved; ptr->reserved = 0; ptr = ptr->nextchar = new listnode('\0'); List[ListIndex++] = ptr; //put it in linear list t++; cpy = ptr; nextstate--; } } if(isspace(*(t+1)) || (*(t+1) == '\0')) { if(ptr->keyword != 0) { Error = 5; } //this was the last character ptr->setkeycode(keywords); //add one state for the last character //protect from state overwriting by a smaller word if(ptr->state == 0) { ptr->state = state; nextstate++; } if(ptr->val == '\0') { //empty and last character - reserve one more state ptr->reserved = nextstate++; } } else { if(ptr->val == '\0') { //empty - save state ptr->state = state; state = nextstate++; } } ptr->val = *t; break; } //not equal - take alternative ptr = ptr->altchar; } if(ptr == NULL) { //not found in alternatives ptr = cpy; if(Start == NULL) { //no start node yet ptr = Start = new listnode(*t); List[ListIndex++] = ptr; //put it in linear list } else { state = ptr->state; ptr = ptr->altchar = new listnode(*t); List[ListIndex++] = ptr; //put it in linear list } //set state number ptr->state = state; ptr->passes++; if(isspace(*(t+1)) || (*(t+1) == '\0')) { //this was the last character ptr->setkeycode(keywords); //reserve one state ptr->reserved = nextstate++; } } else { ptr = cpy; } state = nextstate; } while ((!isspace(*++t)) && (*t != '\0')); return t; } int listtree :: jumptable(char *code) { int i, k, s; s = strlen(code); k = totalstates(); for(i = 1; i <= k; i++) { s += sprintf(code + s, "\tgoto\tparse_state%d\n", i); } return s; } int listtree :: statetable(char *code) { int i, k, s, x; listnode *ptr, *ptr2, *lastptr, *firstptr; char last; s = strlen(code); k = totalstates(); for(i = 0; i <= k; i++) { last = '\0'; //scan through all states while((ptr = searchstate(i)) != NULL) { //state i found if(last == '\0') { //first two lines s += sprintf(code + s, "parse_state%d\n\ \tmovf\tparse_char, w\n", i); s += sprintf(code + s, "\taddlw\t-'%.1s'\n", &ptr->val); firstptr = ptr; } else { s += sprintf(code + s, "\taddlw\t'%.1s'-'%.1s'\n", &last, &ptr->val); } s += sprintf(code + s, "\tskpnz\n"); if((x = ptr->reserved) == 0) { x = ptr->nextchar->state; } s += sprintf(code + s, "\t retlw\t%d\n", keywords + 1 + x); last = ptr->val; lastptr = ptr; } if(last == '\0') { //state not found - lookahead check? ptr2 = searchnextstate2(i); s += sprintf(code + s, "parse_state%d\n\tmovlw\t%d\n", i, ptr2->keyword); //s += sprintf(code + s, "\tmovwf\tparse_state\n"); s += sprintf(code + s, "\tgoto\tparse_state_delimiter\n"); } else { //state found at least once - //print final part of state //4 options: //1) movlw keyword, movwf parse_state, goto parse_state_delimiter // (previous in next-chain state was last character in a keyword) //2) retlw 255 // (not (1), whole words match) //3) goto parse_state_(reserved) // (not (1), not whole words match, further chain is resolved) //4) empty // (not (1), not whole words match, -"-, reserved state is a next state) ptr2 = searchnextstate(firstptr); if((ptr2 != NULL) && (ptr2->keyword != 0)) { //option 1 s += sprintf(code + s, "\tmovlw\t%d\n", ptr2->keyword); //s += sprintf(code + s, "\tmovwf\tparse_state\n"); s += sprintf(code + s, "\tgoto\tparse_state_delimiter\n"); } else { if(ptr2 == NULL) { //not preceder in next-chain s += sprintf(code + s, "\tretlw\t255\n"); } else { if(wholeword) { //option 2 s += sprintf(code + s, "\tretlw\t255\n"); } else { if(lastptr->passes != 1) { s += sprintf(code + s, "\tretlw\t255\n"); } else { if((lastptr->reserved - i) != 1) { //option 3 ptr2 = lastptr; while(ptr2->nextchar != 0) { ptr2 = ptr2->nextchar; } s += sprintf(code + s, "\tgoto\tparse_state%d\n", ptr2->reserved); } } } } } } } return s; } listnode *listtree :: searchstate(int state) { while(searchindex < ListIndex) { if(List[searchindex++]->state == state) { return List[searchindex - 1]; } } searchindex = 0; return NULL; } listnode *listtree :: searchnextstate(listnode *to) { listnode *ptr; searchnextindex = 0; while(searchnextindex < ListIndex) { ptr = List[searchnextindex++]; if(ptr->nextchar == to) { return List[searchnextindex - 1]; } } return NULL; } listnode *listtree :: searchnextstate2(int tostate) { listnode *ptr; searchnextindex = 0; while(searchnextindex < ListIndex) { ptr = List[searchnextindex++]; if(ptr->reserved == tostate) { return List[searchnextindex - 1]; } } return NULL; } //------------------------------------------------------------------------- int main() { llist entries; char Text[TextSize]; //list of keywords int Error = 0; /* Generate header and title */ html_header(); html_begin("Code Generator Results"); /* Read form values */ read_cgi_input(&entries); if(is_field_exists(entries, "Keywords")) { char *x; int len; x = cgi_val(entries, "Keywords"); len = strlen(x); if(len == 0) { Error = 1; } else { if(len <= TextSize) { strcpy(Text, x); } else { Error = 2; } } } else { Error = 1; } if(is_field_exists(entries, "CaseInsensitive")) { Insense = 1; } if(is_field_exists(entries, "Whole")) { Whole = 1; } if(Error == 0) { /* Open preformatted block */ printf("
\n"); /* Call code generation */ Error = generate(Text, Insense, Whole); /* Close preformatted block */ printf("\n"); if(!Error) { TimeStamp(); Banner(); } else { ReportError(Error); } } else { /* Report error */ ReportError(Error); } html_end(); list_clear(&entries); return 0; } void ReportError(char Err) { printf("
\n", "%");
printf(" \n"); printf("Nikolai Golovchenko\n"); printf(" | \n");
printf("