#include #include #include #include #include #include #include #define begin { #define end } #define HASH_SIZE 51 #define NODE_SIZE 50 //define the hash indices of pre-inserted symbols #define LEFT_PAREN -13 #define RIGHT_PAREN -43 #define PLUS -6 #define MINUS -29 #define PRODUCT -24 #define LESSTHAN -16 #define MORETHAN -4 #define TRUE -39 #define FALSE -8 #define EQ -10 #define EQUAL -9 #define EQUALTO -35 #define NUMBER -50 #define SYMBOL -47 #define QUOTE -26 #define CAR -3 #define CDR -30 #define CONS -37 #define COND -38 #define DISPLAY -27 #define DEFINE -36 #define NUL -45 #define ELSE -33 #define LAMBDA -18 #define NIL 0 #define OVERFLOW 10002 void initialize(void); //hash table functions int hashFunc(char* symbol); eeprom char* getSymbol(int index); void setPointer(int index, int pointer); int getPointer(int index); int insert(char* symbol); int getIndex(char* symbol); //interpreter functions char* GetNextToken(char* command); char* Preprocessing(char* command, char* newcommand); void Concatenate(char* a, char* b); void make_hash(char* newcommand); int Read(char* newcommand); int Eval(int root); int GetFirstArg(int root); int GetSecondArg(int root); int GetHashValue(char* newarg); int CheckStructure(int arg1, int arg2); int isNumber(int root); void PushAndSet(int root); void PopAndReset(int root); void upush(int* n); int* upop(); void printarray(int root); //memory functions char* flashtosram(flash char* f_str, char* rr_str); char* eepromtosram(eeprom char* e_str, char* rr_str); void eepromstrcpy(eeprom char* e_str, char* rr_str); //variables for non-blocking receiving communication with hyperterm unsigned char r_index; //current string index unsigned char str1[90]; //input string unsigned char r_ready; //flag for receive done unsigned char r_char; //current character //returned string from getNextToken unsigned char str2[90]; //strings for preprocessing unsigned char newcommand[90]; unsigned char newcommand2[90]; //returned strings from memory functions unsigned char r_str[10]; unsigned char r_str2[10]; unsigned char r_str3[10]; //indices //i = current position on the string //j = previous position on the string //q = index for ustack int i, j, q; //hash indices which are not empty int indextable[HASH_SIZE]; //the number of symbols in the hash table int index_size=0; //which node is next available? int FreeList=1; //the number of parenthesises int L, R; eeprom struct HashEntry { char symbol[10]; //if the symbol is pointer, it points to the other hashentry or the node array int pointer; }; eeprom struct HashEntry table[HASH_SIZE]; eeprom int nodearray[NODE_SIZE][4]; //stack for executing user-define functions int ustack[10][2]; //symbols to be inserted at the beginning flash unsigned char* c_array[] = {"\0", "(", ")", "+", "-", "*", "<", ">", "#t", "#f", "eq?", "number?", "symbol?", "quote", "car", "cdr", "display", "define", "null?", "equal?", "cons", "cond", "else", "=", "lambda", "( lambda (", "( quote"}; //********************************************************** //UART character-ready ISR interrupt [USART_RXC] void uart_rec(void) begin r_char=UDR; //get a char UDR=r_char; //then print it //build the input string //if r_char is backspace if (r_char == 8) begin //print blank to overwrite UDR = 32; if(r_index != 0) r_index--; delay_us(10000); //backspace again UDR = 8; end else if(r_char != '\r') begin str1[r_index++]=r_char; end else begin putchar('\n'); //use putchar to avoid overwrite str1[r_index]=0x00; //zero terminate r_ready=1; //signal cmd processor UCSRB.7=0; //stop rec ISR end end //********************************************************** //Entry point and task scheduler loop void main(void) begin int root, result; initialize(); while(1) begin //if receiving done if (r_ready) begin i = 0; //check the number of parenthesises while(str1[i] != '\0') { if(str1[i] == 40) L++; else if(str1[i] == 41) R++; i++; } if ( L == R ) begin r_ready=0; //make the command not case sensitive for(i=0;str1[i];i++) str1[i] = tolower(str1[i]); //for debugging, print the received string printf("%d, %s\n\r", strlen(str1), str1); //initialize indices i = 0; j = 0; Preprocessing(str1, newcommand); //for debuggin, print the string after preprocessing printf("%d, %s\n\r", strlen(newcommand), newcommand); //insert new symbols, if any make_hash(newcommand); //initialize indices i = 0; j = 0; //make a node tree for the command, and return the root node root = Read(newcommand); //for debuggin, print the root printf("Root : %d\n\r", root); //if there is no node available if(root==OVERFLOW) { printf("Error : Stack overflow error.\n\r\n"); } else { //execute the command result = Eval(root); //if result<0, it is hash index, so get symbol from hash table if(result<0) printf("Result : %s\n\r", eepromtosram(getSymbol(result), r_str)); //if result>0, it is an array of nodes, so print array else if(result>0) { printf("Result : "); printarray(result); printf("\n\r"); } //if result=0, it is NULL, and this is the case when the command was the kind of define, or the return value was actually NULL printf("\n"); } end else printf("Error : The numbers of left and right parenthesises do not match.\n\r\n"); //start to receive the next command L = 0; R = 0; r_ready=0; r_index=0; UCSRB.7=1; end end end //********************************************************** //Set it all up void initialize(void) begin //serial setop for debugging using printf, etc. UCSRB = 0x18 ; UBRRL = 103 ; putsf("\r\nStarting...\r\n"); //crank up the ISRs #asm sei #endasm //insert default symbols to hash table for(i=0;i<25;i++) begin //insert(flashtosram(c_array[i],r_str)); //for debuggin, print to check inserting is actually working printf("%d : %d", index_size+1, insert(flashtosram(c_array[i],r_str))); printf(" %s", eepromtosram(getSymbol(getIndex(flashtosram(c_array[i],r_str))), r_str)); printf(" %d\n\r", getIndex(flashtosram(c_array[i],r_str))); end //initialize nodes for(i=0;i=HASH_SIZE) k=k-HASH_SIZE; if(k==-indextable[l]) { k++; l=-1; } l++; } index_size++; indextable[index_size-1]=-k; indextable[index_size]='\0'; eepromstrcpy(table[k].symbol, symbol); table[k].pointer = 0; return -k; } int getIndex(char* symbol) { int exist=10002; int k=0; char r_str_local[10]; while(k0); Concatenate(newcommand, flashtosram(c_array[2],r_str)); } //otherwise, no preprocessing required else { Concatenate(newcommand, token); } token=GetNextToken(command); } return newcommand; } //insert new symbols to hash table void make_hash(char* newcommand) { char* token; i=0,j=0; token=GetNextToken(newcommand); while(token[0]!='\0') { if( (token[0]=='(') || (token[0]==')') ) { token=GetNextToken(newcommand); } else { if(getIndex(token)!= 10002) { token=GetNextToken(newcommand); } //if new symbol, insert else { insert(token); token=GetNextToken(newcommand); } } } } //make a node tree for the command, and return the root node int Read(char* newcommand) { int token_hash_value; int first=1; int temp; int root=NIL; token_hash_value =getIndex(GetNextToken(newcommand)); //if the first token is LEFT_PAREN if(token_hash_value==LEFT_PAREN) { token_hash_value=getIndex(GetNextToken(newcommand)); while(token_hash_value!=RIGHT_PAREN) { //check if there is a free node left //if so, get the free node //if not, return OVERFLOW if(first==1) { if(FreeList==0) { return OVERFLOW; } temp=FreeList; FreeList=nodearray[FreeList][3]; root=temp; } else { if(FreeList==0) { return OVERFLOW; } nodearray[temp][1]=FreeList; FreeList=nodearray[FreeList][3]; temp=nodearray[temp][1]; } first=0; //if there is another LEFT_PAREN inside the parenthesises, recursively call Read if(token_hash_value==LEFT_PAREN) { i = j; nodearray[temp][0]=Read(newcommand); token_hash_value=getIndex(GetNextToken(newcommand)); } //if not, add node for the token else { nodearray[temp][0]=token_hash_value; token_hash_value=getIndex(GetNextToken(newcommand)); } } if(first==0) nodearray[temp][1]=NIL; return root; } //if the first token is not LEFT_PAREN, it means the command is symbol, so return the hash index for the symbol else return token_hash_value; } int Eval(int root) { char newarg[10]; int newmemory, exe; signed long a; //if the root is negative, it means that it is the hash index //if the symbol is number, return it if((root<0)&&(isNumber(root))) return root; //if the symbol is not number, return the pointer else if(root<0) return getPointer(root); //if the root is positive, it means that it is pointing to the node tree //switch upon the functon name switch(nodearray[root][0]) { case PLUS: { //get the first argument a = atol(eepromtosram(getSymbol(GetFirstArg(root)), r_str2)); //add the second argument to the first argument a += atol(eepromtosram(getSymbol(GetSecondArg(root)), r_str3)); sprintf(newarg, "%ld", a); //return the hash index of the result return GetHashValue(newarg); } case MINUS: { a = atol(eepromtosram(getSymbol(GetFirstArg(root)), r_str2)); a -= atol(eepromtosram(getSymbol(GetSecondArg(root)), r_str3)); sprintf(newarg, "%ld", a); return GetHashValue(newarg); } case PRODUCT: { a = atol(eepromtosram(getSymbol(GetFirstArg(root)), r_str2)); a *= atol(eepromtosram(getSymbol(GetSecondArg(root)), r_str3)); sprintf(newarg, "%ld", a); return GetHashValue(newarg); } case LESSTHAN: { a = atol(eepromtosram(getSymbol(GetFirstArg(root)), r_str2)); if( a < atol(eepromtosram(getSymbol(GetSecondArg(root)), r_str3)) ) return TRUE; else return FALSE; } case MORETHAN: { a = atol(eepromtosram(getSymbol(GetFirstArg(root)), r_str2)); if( a > atol(eepromtosram(getSymbol(GetSecondArg(root)), r_str3)) ) return TRUE; else return FALSE; } //check if the value of the two arguments are same case EQUALTO: { if(GetFirstArg(root)==GetSecondArg(root)) return TRUE; else return FALSE; } //check if the pointer of the two arguments are same case EQ: { if(nodearray[(nodearray[root][1])][0]==nodearray[(nodearray[(nodearray[root][1])][1])][0]) return TRUE; else return FALSE; } //check if the two arguments are the arrays consisting of the same elements case EQUAL: { if(GetFirstArg(root)==GetSecondArg(root)) return TRUE; else return CheckStructure(GetFirstArg(root), GetSecondArg(root)); } case NUMBER: { if(isNumber(Eval(nodearray[(nodearray[root][1])][0]))) return TRUE; else return FALSE; } case SYMBOL: { if(isNumber(Eval(nodearray[(nodearray[root][1])][0]))) return FALSE; else return TRUE; } case NUL: { if(nodearray[Eval(nodearray[(nodearray[root][1])][0])][0]==NIL) return TRUE; else return FALSE; } //return the content of quote //it could be an array, or a single symbol which is not number case QUOTE: { return nodearray[(nodearray[root][1])][0]; } //return the first element of the array case CAR: { return nodearray[Eval(nodearray[(nodearray[root][1])][0])][0]; } //return the array without the first element case CDR: { return nodearray[Eval(nodearray[(nodearray[root][1])][0])][1]; } //prepend the first argument to the second argument which is array case CONS: { newmemory=FreeList++; nodearray[newmemory][0]=nodearray[(nodearray[root][1])][0]; nodearray[newmemory][1]=Eval(nodearray[(nodearray[(nodearray[root][1])][1])][0]); return newmemory; } case COND: { a=nodearray[root][1]; for(a;nodearray[a][1]!=0;a=nodearray[a][1]) { if((Eval(nodearray[(nodearray[a][0])][0])==TRUE)||(nodearray[(nodearray[a][0])][0]==ELSE)) return Eval(nodearray[(nodearray[(nodearray[a][0])][1])][0]); } if((Eval(nodearray[(nodearray[a][0])][0])==TRUE)||(nodearray[(nodearray[a][0])][0]==ELSE)) return Eval(nodearray[(nodearray[(nodearray[a][0])][1])][0]); else return 0; } case DISPLAY: { return Eval(nodearray[(nodearray[root][1])][0]); } //set the pointer of the first argument to the second argument case DEFINE: { setPointer(nodearray[(nodearray[root][1])][0], Eval(nodearray[(nodearray[(nodearray[root][1])][1])][0])); return 0; } case LAMBDA: { return root; } //if it is user-define function default: { //push the pointer of the symbols which are used by the user-define function to ustack PushAndSet(root); exe = Eval(nodearray[(nodearray[(nodearray[Eval(nodearray[root][0])][1])][1])][0]); //pop from ustack, and recover the original pointers PopAndReset(root); return exe; } } } int GetFirstArg(int root) { return Eval(nodearray[(nodearray[root][1])][0]); } int GetSecondArg(int root) { return Eval(nodearray[(nodearray[(nodearray[root][1])][1])][0]); } //after Eval, get the hash index of the result //if the result is a new symbol, insert it to hash table, and return its hash index int GetHashValue(char* newarg) { if(getIndex(newarg)==10002) { return insert(newarg); } else return getIndex(newarg); } //for EQUAL, check if two arrays consist of the same elements int CheckStructure(int arg1, int arg2) { int tmp1; int tmp2; for(arg1;(nodearray[arg1][1]!=0)&&(nodearray[arg2][1]!=0);arg1=nodearray[arg1][1]) { if( (nodearray[(nodearray[arg1][0])][0] == QUOTE)||(getPointer(nodearray[arg1][0])!=0)) tmp1 = Eval(nodearray[arg1][0]); else tmp1 = nodearray[arg1][0]; if( (nodearray[(nodearray[arg2][0])][0] == QUOTE)||(getPointer(nodearray[arg2][0])!=0)) tmp2 = Eval(nodearray[arg2][0]); else tmp2 = nodearray[arg2][0]; if( (tmp1<0) && (tmp2<0) ) { if(tmp1!=tmp2) return FALSE; } else if( tmp1*tmp2<=0 ) return FALSE; else { if(nodearray[(nodearray[arg1][0])][0] == QUOTE) { if(nodearray[(nodearray[arg2][0])][0] == QUOTE) CheckStructure(tmp1, tmp2); else CheckStructure(tmp1, nodearray[arg2][0]); } else { if(nodearray[(nodearray[arg2][0])][0] == QUOTE) CheckStructure(nodearray[arg1][0], tmp2); else CheckStructure(nodearray[arg1][0], nodearray[arg2][0]); } } arg2 = nodearray[arg2][1]; } if( (nodearray[(nodearray[arg1][0])][0] == QUOTE)||(getPointer(nodearray[arg1][0])!=0)) tmp1 = Eval(nodearray[arg1][0]); else tmp1 = nodearray[arg1][0]; if( (nodearray[(nodearray[arg2][0])][0] == QUOTE)||(getPointer(nodearray[arg2][0])!=0)) tmp2 = Eval(nodearray[arg2][0]); else tmp2 = nodearray[arg2][0]; if( (tmp1<0) && (tmp2<0) ) { if(tmp1!=tmp2) return FALSE; } else if( tmp1*tmp2<=0 ) return FALSE; else { if(nodearray[(nodearray[arg1][0])][0] == QUOTE) { if(nodearray[(nodearray[arg2][0])][0] == QUOTE) CheckStructure(tmp1, tmp2); else CheckStructure(tmp1, nodearray[arg2][0]); } else { if(nodearray[(nodearray[arg2][0])][0] == QUOTE) CheckStructure(nodearray[arg1][0], tmp2); else CheckStructure(nodearray[arg1][0], nodearray[arg2][0]); } } if((nodearray[arg1][1]!=0)||(nodearray[arg2][1]!=0)) return FALSE; else return TRUE; } //check if the symbol is number int isNumber(int root) { int i; char* arg; arg = eepromtosram(getSymbol(root), r_str); if(strlen(arg)==0) return 0; for(i=0;i57)) { if((i!=0)||(arg[i]!=45)) return 0; } } return 1; } //push the pointer of the symbols which are used by the user-define function to ustack //set the pointers to the given arguments void PushAndSet(int root) { int name; int position; int p=0; int sE[2]; int v[100]; name = nodearray[(nodearray[Eval(nodearray[root][0])][1])][0]; position = nodearray[root][1]; while(position!=NIL) { v[p]=Eval(nodearray[position][0]); position=nodearray[position][1]; p++; } p=0; while(name!=NIL) { sE[0]=nodearray[name][0]; sE[1]=getPointer(sE[0]); upush(sE); setPointer(sE[0], v[p]); name=nodearray[name][1]; p++; } } ////pop from ustack, and recover the original pointers void PopAndReset(int root) { int trace; int* sE; trace = nodearray[(nodearray[Eval(nodearray[root][0])][1])][0]; while(trace!=NIL) { sE=upop(); setPointer(sE[0], sE[1]); trace = nodearray[trace][1]; } } void upush(int* n) { ustack[q][0]=n[0]; ustack[q][1]=n[1]; q++; } int* upop() { return ustack[--q]; } //if the result is an array, print the result using this function void printarray(int root) { char r_str_local[10]; int tmp; printf("( "); for(root;(nodearray[root][1])!=0;root=nodearray[root][1]) { //if the element is a symbol if(nodearray[root][0]<0) { tmp = Eval(nodearray[root][0]); //if the element is a number if(tmp<0) printf("%s ", eepromtosram(getSymbol(tmp), r_str_local)); //if the element is a symbol pointing an array else if(tmp>0) printarray(tmp); } //if the element is an array else { //if it is a symbol surrounded by quote //print the symbol, not the number pointed by the symbol if(nodearray[(nodearray[root][0])][0] == QUOTE) { tmp = Eval(nodearray[root][0]); if(tmp<0) printf("%s ", eepromtosram(getSymbol(tmp), r_str_local)); else if(tmp>0) printarray(tmp); } //otherwise recursively call printarray else printarray(nodearray[root][0]); } } if(nodearray[root][0]<0) { tmp = Eval(nodearray[root][0]); if(tmp<0) printf("%s ", eepromtosram(getSymbol(tmp), r_str_local)); else if(tmp>0) printarray(tmp); } else { if(nodearray[(nodearray[root][0])][0] == QUOTE) { tmp = Eval(nodearray[root][0]); if(tmp<0) printf("%s ", eepromtosram(getSymbol(tmp), r_str_local)); else if(tmp>0) printarray(tmp); } else printarray(nodearray[root][0]); } printf(") "); } //********************************************************** //Memory related functions //some functions only take arguments of the type SRAM, so we need converting functions char* flashtosram(flash char* f_str, char* rr_str) { int idx = 0; while(f_str[idx] != '\0') { rr_str[idx] = f_str[idx]; idx++; } rr_str[idx] = f_str[idx]; return rr_str; } char* eepromtosram(eeprom char* e_str, char* rr_str) { int idx = 0; while(e_str[idx] != '\0') { rr_str[idx] = e_str[idx]; idx++; } rr_str[idx] = e_str[idx]; return rr_str; } void eepromstrcpy(eeprom char* e_str, char* rr_str) { int idx = 0; while(rr_str[idx] != '\0') { e_str[idx] = rr_str[idx]; idx++; } e_str[idx] = rr_str[idx]; }