byAlex Feb2013 GNU GCC 、 MDK编译测试
这是一个通用字符串指令解释器,并且已经实现了四条指令(help、ver、echo、sort),方便移植的时候测试。
C++测试例程
#include <iostream>
#include <cstdio>
extern "C"{
#include "interpretor.h"
}
using namespace std;
extern char itpin[ITPBUFSZ],itpout[ITPBUFSZ];
int main(void){
do{
cout<<"$ ";
gets(itpin);
interpret();
cout<<itpout;
}while(1);
return 0;
}
C嵌入式应用例程(_recv函数片段,应用于telnet指令解释):
for(_di=0;_di<name->length;_di++)itpin[_di]=*(name->bytes+_di);
itpin[_di]='\0';
interpret();
tcp_write(pcb, itpout, strlen(itpout), 1);
FAQ
怎样编写一条指令?
所有需要的数据(至少是目前已知的)都在itpin数组中,借助已有的工具函数提取需要的信息,经过特定算法的加工产生了指令的结果反馈,然后通过格式化的输出方式输出到itpout数组中(如借用sprintf,strcat等),这样一条指令的处理流程就完成了。
如何添加指令?
- 仿照其他指令编写相应函数
- 仿照其他指令在mycmds中添加 “名称-指针 对”
它支持怎样形式的指令?
一般类似于UNIX 或者DOS的命令,即以一个指令的关键字开头,后面跟上若干参数,互相以至少一个空格相隔。
指令缓冲区默认设置了256字节的长度,也就是可以输入255个字符,如果需要修改,只要修改ITPBUFSZ宏就可以了。
提供了几个工具函数:获得参数、获得整数型参数、获得参数位置、获得参数个数
这也就意味着目前可以支持的解释功能有:自动映射指令处理程序、处理可变参数、处理数字(正数,可带一个字符的后缀,如 200m)
为什么采用“名称-指针 对”结构数组完成指令的映射?
通过这样的结构最简单得实现了指令的
自动映射,如果要添加一个指令,不需要修改interpret函数了,写好对应处理程序,再加一条映射就可以了。
如果需要枚举所有支持的指令也很简单,见help指令的实现。
interpretor.h
#ifndef __INTERPRETOR_H_
#define __INTERPRETOR_H_
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ITPBUFSZ 256 //输入/输出缓冲区大小
#define ITPARGSZ 80 //参数(单个)缓冲大小
#define ITPISTSZ 12 //表示整数的字符串大小
void interpret(void); //从itpin读取指令解释执行并把结果输出到itpout
#endif
interpretor.c
#include "interpretor.h"
char itpin[ITPBUFSZ],itpout[ITPBUFSZ]; //输入/输出缓冲区
int itpatoi(char *suf,const char *loc); //从loc所指向的位置开始截取一个参数,转换成整数型返回,并把后缀字符(如果存在)输出到suf
char* itpstrcpy(char *buf,const char *loc);//从loc所指向的位置开始截取一个参数,复制到buf,并返回指向buf的指针
char* itploc(int i); //获取指向第i个参数的指针
int itpargc(void); //获取参数个数
//help指令:help
//显示解释器具体实现的功能,并枚举所有已映射指令
void helpcmd(void);
//ver指令:ver
//显示版本等信息
void vercmd(void){
strcpy(itpout,"TELROV byAlex Feb. 2013\r\n");
}
//sort指令(可以用来测试整型参数提取(itpatoi函数)是否正确运行):sort ...
//升序排序正整数整数并输出(用一个空格隔开),例:
//sort 40 33 21
//21 33 40
void sortcmd(void){
int data[25],n,i,j,t;
char stmp[ITPISTSZ];
n=itpargc()-1;
if(n>0){
for(i=0;i<n;i++)data[i]=itpatoi(NULL,itploc(i+1));
for(i=n-1;i>0;i--){
for(j=0;j<=i;j++){
if(data[j]>data[i]){
t=data[j];
data[j]=data[i];
data[i]=t;
}
}
}
itpout[0]='\0';
for(i=0;i<n;i++){
sprintf(stmp,"%d ",data[i]);
strcat(itpout,stmp);
}
strcat(itpout,"\r\n");
}
else strcpy(itpout,"No data.\r\n");
}
//echo指令(可以用来测试参数提取(itpstrcpy函数)是否正确运行):echo ...
//按照原来的次序输出各个参数(用一个空格隔开),例:
//echo quick brown fox jumps over the lazy dog
//quick brown fox jumps over the lazy dog
void echocmd(void){
int n,i;
char stmp[ITPARGSZ];
n=itpargc()-1;
if(n>0){
itpout[0]='\0';
for(i=0;i<n;i++){
itpstrcpy(stmp,itploc(i+1));
strcat(itpout,stmp);
strcat(itpout," ");
}
strcat(itpout,"\r\n");
}
else itpout[0]='\0';
}
//已映射的指令个数
#define CMDCT (sizeof(mycmds)/sizeof(struct mycmd))
//指令映射(“名称-指针 对”形式的结构数组)
struct mycmd{
char *name;
void (*func)(void);
}
mycmds[]={
{"help",helpcmd},
{"ver",vercmd},
{"sort",sortcmd},
{"echo",echocmd}
};
//help指令:help
//显示解释器具体实现的功能,并枚举所有已映射指令
void helpcmd(void){
int rmsp,i;
const char description[]="TELROV:Rover commander using telnet.\r\n";
strcpy(itpout,description);
rmsp=ITPBUFSZ-7-strlen(description);
for(i=0;i<CMDCT;i++){
if(rmsp>strlen(mycmds[i].name)){
strcat(itpout,mycmds[i].name);
strcat(itpout,"\t");
}
else break;
}
if(i!=CMDCT)strcat(itpout," ...");
strcat(itpout,"\r\n");
}
//从itpin读取指令解释执行并把结果输出到itpout
void interpret(void){
int icmd;char stmp[ITPARGSZ];
if(itpargc()>0){
itpstrcpy(stmp,itploc(0));
for(icmd=0;icmd<CMDCT;icmd++)if(strcmp(stmp,mycmds[icmd].name)==0)break;
if(icmd<CMDCT)mycmds[icmd].func();
else{
strcpy(itpout,"Uninterpretable:'");
strcat(itpout,stmp);
strcat(itpout,"'\r\n");
}
}
else itpout[0]='\0';
}
//从loc所指向的位置开始截取一个参数,复制到buf,并返回指向buf的指针
char* itpstrcpy(char *buf,const char *loc){
const char *p;int i=0;
if(buf==NULL||loc==NULL)return NULL;
else
for(p=loc;*p!=' '&&*p!='\r'&&*p!='\n'&&*p!='\0';p++)
buf[i++]=*p;
buf[i]='\0';
return buf;
}
//从loc所指向的位置开始截取一个参数,转换成整数型返回,并把后缀字符(如果存在)输出到suf
int itpatoi(char *suf,const char *loc){
char strn[ITPISTSZ];int i=0;const char *p;
if(loc==NULL)return suf!=NULL?(*suf=0):0;
else{
for(p=loc;*p!=' '&&*p!='\r'&&*p!='\n'&&*p!='\0';p++){
if(*p>='0'&&*p<='9')strn[i++]=*p;
else if(suf!=NULL){*suf=*p;break;}
}
strn[i]='\0';
return atoi(strn);
}
}
//获取指向第i个参数的指针
char* itploc(int i){
char *p,pre=' ';int ct=0;
for(p=itpin;*p!='\0';p++){
if(*p!=' '){if(*p!='\r'&&*p!='\n'&&ct==i)return p;}
else if(pre!=' ')ct++;
pre=*p;
}
return NULL;
}
//获取参数个数
int itpargc(void){
const char *p;char pre=' ';int ct=0;
for(p=itpin;*p!='\0';p++){
if(*p!=' '){
if(*p=='\r'||*p=='\n')break;
if(pre==' ')ct++;
}
pre=*p;
}
return ct;
}