Listing 2 The message interpreter and assembler for the embedded controller, implemented on a PC

/* pars.c */
/* no copyrights claimed */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "parsdef.h"

static toDoList toDo[MAX_STATEMENTS];
static char stringPool[STRINGPOOL];
static char *pPool, *poolEnd;
static char message[MESSAGELENGTH];
static char *messList[]= {
   "EMPTY","error","empty","assign","request",
   "to_eeprom","is","command","integer","float",
   "name","name_error","op_error","val_error",
   "end_error","pool_error"
};

main()
{
   while(1) {
      pPool= stringPool;
      poolEnd= stringPool+STRINGPOOL-1;
      printf("\nmessage: ");
      gets(message);
      if(message[0]=='.') break;
      Parse(message, toDo);
      PrintToDo(toDo);
      DoCommands(toDo);
   }
}

/* first, the parsing */

void Parse(char *message, toDoList *pToDo)
{
   char *pC, token[MAX_TOKEN_LEN+1];
   int type, i;
   pC= message;
   for(i=0; i<MAX_STATEMENTS; i++) {
      (pToDo+1)->command= EMPTY; /* mark end */
      if(*pC=='\0'){pToDo->command= EMPTY; return;}
      /* get name */
      pC= GetNextToken(pC, token, &type);
      if(StoreToken(&pToDo->name, token) != 0)
         { pToDo->command=POOL_ERROR; return; }
      if((type==ERROR)||(type!=NAME))
         { pToDo->command= NAME_ERROR; return;}
      if(*pC=='\0') {pToDo->command=EMPTY; return;}
      /* get operator */
      pC= GetNextToken(pC, token, &type);
      if(type==ERROR)
         {pToDo->command=OP_ERROR; return;}
      pToDo->command= type;
      /* get value */
      if((type==ASSIGN)||(type==TO_EEPROM)||
         (type==IS)) {
         if(*pC=='\0')
            {pToDo->command=VAL_ERROR; return;}
         pC= GetNextToken(pC, token, &type);
         pToDo->type= type;
         if(type==INTEGER)
            pToDo->value= atoi(token);
         else {pToDo->command= VAL_ERROR; return;}
      }
      else pToDo->type= INTEGER;
      if(pToDo->command== EMPTY) return;
      pToDo++;
   }
   pToDo->command= END_ERROR;
   return;
}

char *GetNextToken(char *begin, char *token, int type)
{
   char *pC, *pT;
   int i;
   pC= begin;
   pT= token;
   *token='\0';
   *type= EMPTY;
   if(*pC == '\0') {return pC;}
   /* remove leading spaces */
   while(*pC=='') pC++;
   if(*pC=='\0') return pC;
   if(isalpha(*pC)) { /* name */
      *type= NAME;
      *pT++= *pC++;
      for(i=1; i<MAX_TOKEN_LEN; i++) {
         if((isalpha(*pC)) || (isdigit(*pC))
            ||(*pC=='_')) *pT++= *pC++;
         else {
            *pT= '\0';
            return pC;
         }
      }
      *type= ERROR;
   return pC;
   }
   else if((isdigit(*pC))||(*pC=='+')||)
      (*pC=='-')) { /* number */
      *pT++= *pC++;
      for(i=1; i<MAX_TOKEN_LEN; i++) {
         if(isdigit(*pC)) *pT++= *pC++;
         else {
            *pT= '\0';
            *type= INTEGER;
            return pC;
         }
      }
      *type= ERROR;
      return pC;
   }
   else if(*pC== '=') *type= ASSIGN;
   else if(*pC== '?') *type= REQUEST;
   else if(*pC== '>') *type= TO_EEPROM;
   else if(*pC== ':') *type= IS;
   else if(*pC== '!') *type= COMMAND;
   else {*type= ERROR; return ++pC;}
   return ++pC;
}

int StoreToken(char **ppName, char *token)
{
   int length;
   *ppName= pPool;
   length= strlen(token)+1;
   if((pPool+length)>=poolEnd) return -1;
   strcpy(pPool, token);
   pPool+= length;
   return 0;
}

/* and now, the action */

static symTabEntry symTab[]= {

   {"reset"  ,  0  , Reset, -1},
   {"status" , 35  , NULL , -1},
   {"temp"   , 16  , NULL ,  20}
};

void PrintToDo(toDoList *toDo)
{
   while(toDo->command != EMPTY) {
      printf("\n %s %s '%s'",
         messList[toDo->command],
         messList[toDo->type], toDo->name);
      if(toDo->type==INTEGER)
         printf(" %d", toDo->value);
      toDo++;
   }
}

int SymCmp(symTabEntry *a, symTabEntry *b)
{
   return strcmp(a->name, b->name);
}

symTabEntry *FindSymbol(char *pName)
{
   symTabEntry dummy, *p;
   dummy.name= pName;
   p= (symTabEntry*) bsearch(&dummy, symTab,
      sizeof(symTab)/sizeof(symTabEntry),
      sizeof(symTabEntry),
      (int(*)(const void*, const void*))SymCmp);
   return p;
}

char *Reset(char *pC)
{
   printf("\nExecuting 'Reset'");
   return pC;
}

void DoCommands(toDoList *pToDo)
{
   char *txBuffer, *pTx;
   txBuffer= pTx= TxBuffer();
   *pTx= '\0';
   while(pToDo->command != EMPTY) {
   switch(pToDo->command) {
      case ERROR:
      case NAME_ERROR:
      case OP_ERROR:
      case VAL_ERROR:
      case END_ERROR:
      case POOL_ERROR:
      pTx= SayError(pToDo, pToDo->command, pTx);
      break;
      case ASSIGN:    pTx= Assign(pToDo, pTx);
                    break;
      case REQUEST:   pTx= Request(pToDo, pTx);
                    break;
      case TO_EEPROM: pTx= ToEeprom(pToDo, pTx);
                    break;
      case COMMAND:   pTx= RunCommand(pToDo, pTx);
                    break;
           default:        break;
      }
   ++pToDo;
   }
   printf("\ntxBuffer: '%s'\n", txBuffer);
}

char *SayError(toDoList *pToDo, int err, char *pC)
{
   char str[MAX_TOKEN_LEN+1], *pS;
   pS= pToDo->name;
   while(*pC++=*pS++);
   pC--;
   *pC++='#';
   sprintf(str,"%-d", err);
   pS= str;
   while(*pC++= *pS++);
   return --pC;
}

char *Assign(toDoList *pToDo, char *pTx)
{
   symTabEntry *pSym;
   pSym= FindSymbol(pToDo->name);
   if(pSym==NULL) {
      pTx= SayError(pToDo, UNDEF_SYMB, pTx);
      return pTx;
   }
   if(pToDo->type==INTEGER) pSym->ival= pToDo->value;
   if(pSym->func!=NULL) pTx= (*pSym->func)(pTx);
   return pTx;
}

char *Request(toDoList *pToDo, char *pTx)
{

   symTabEntry *pSym;
   char *pS, str[MAX_TOKEN_LEN+1];
   pSym= FindSymbol(pToDo->name);
   if(pSym==NULL) {
      pTx= SayError(pToDo, UNDEF_SYMB, pTx);
      return pTx;
   }
   pS= pToDo->name;
   while(*pTx++=*pS++);
   pTx--;
   *pTx++= '=';
   if(pToDo->type==INTEGER)
      sprintf(str,"%-d", pSym->ival);
   pS= str;
   while(*pTx++=*pS++);
   if(pSym->func!=NULL) pTx= (*pSym->func)(pTx);
   return --pTx;
}

char *ToEeprom(toDoList *pToDo, char *pTx)
{
   symTabEntry *pSym;
   pSym= FindSymbol(pToDo->name);
   if(pSym==NULL) {
      pTx= SayError(pToDo, UNDEF_SYMB, pTx);
      return pTx;
   }
   if(pSym->eeOffset<O) {
      pTx= SayError(pToDo, NOT_EEPROM, pTx);
      return pTx;
   }
   if(pToDo->type==INTEGER) {
      pSym->ival= pToDo->value;
      WriteEeprom(pSym, INTEGER];
   }
   if(pSym->func!=NULL) pTx= (*pSym->func)(pTx);
   return pTx;
   }

char *RunCommand(toDoList *pToDo, char *pTx)
{
   symTabEntry *pSym;
   pSym= FindSymbol(pToDo->name);
   if(pSym==NULL) {
      pTx= SayError(pToDo, UNDEF_SYMB, pTx);
      return pTx;
   }
   if(pSym->func!=NULL) pTx= (*pSym->func)(pTx);
   else {
      pTx=SayError(pToDo, UNDEF_FUNC, pTx);
      return pTx;
   }
   return pTx;
}

char *TxBuffer(void)
{
   static char buffer[200];
   return buffer;
}

void WriteEeprom(symTabEntry *pSym, int type)
{
   if(type==INTEGER) printf(
      "\nTo EE, type: %d off: %d val: %d\n",
      type, pSym->eeOffset, pSym->ival);
   return;
}

/* End of File */