Feb 14

trans程序的源代码在Msys下用gcc编译调试通过。

使用说明:trans  [-r/-s] srcfile objfile

    其中,-R 将摩斯码翻译成英文;
          -S 将英语翻译成摩斯码。
          srcfile为需要翻译的文本文件。运行成功后结果会保存在objfile文件中。

    注意:若是翻译英文,须保证所有字母均为大写字母。且标点符号仅可为“.”和“,”

代码已上传至github https://github.com/longqzh/MorseCode_Translator

/* *******************************
 *
 * Translator for Morse Code
 *
 * Author: Long Qianzhi
 * Date:2010/1/28
 *
 * *******************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 39

struct table{
	char letter;
	char mor[8];
}table[]={
	{'A',".-"},{'B',"-..."},{'C',"-.-."},
	{'D',"-.."},{'E',"."},{'F',"..-."},
	{'G',"--."},{'H',"...."},{'I',".."},
	{'J',".---"},{'K',"-.-"},{'L',".-.."},
	{'M',"--"},{'N',"-."},{'O',"---"},
	{'P',".--."},{'Q',"--.-"},{'R',".-."},
	{'S',"..."},{'T',"-"},{'U',"..-"},
	{'V',"...-"},{'W',".--"},{'X',"-..-"},
	{'Y',"-.--"},{'Z',"--.."},{'0',"-----"},
	{'1',".----"},{'2',"..---"},{'3',"...--"},
	{'4',"....-"},{'5',"....."},{'6',"-...."},
	{'7',"--..."},{'8',"---.."},{'9',"----."},
	{'.',".-.-.-"},{',',"--..--"},{' ',".--.-."},
	{'\n',""}
};

FILE *infp=NULL, *outfp=NULL;

void check_file(char *in, char *out)
{
	if((infp=fopen(in,"r"))==NULL){
		printf("\nCan't open source file : %s\n", in);
		exit(1);
	}
	else if ((outfp=fopen(out,"w"))==NULL){
		printf("\nCan't open output file : %s\n", out);
		exit(1);
	}
	return;
}

int file_size(FILE *fp)
{
	int fsize=0;
	char c;
	while((c=fgetc(fp))!=EOF)
		fsize++;
	rewind(fp);
	return fsize;
}

char* make_buf(int n)
{
	char *pstr;
	pstr=(char *)malloc(n*sizeof(char));
	if(pstr==NULL){
		printf("\nMalloc failed!\n");
		exit(1);
	}
	return pstr;
}

void m2t()
{
	char *buffer;
	int fnum,n=0,i=0;
	char tmp[8]="";

	/* Read all of the data from srcfile to buffer.*/
	fnum=file_size(infp);
	buffer=make_buf(fnum+1);
	if((fread(buffer,sizeof(char),fnum,infp))!=fnum){
		printf("\nSomething wrong about reading file!\n");
		exit(1);
	}
	*(buffer+fnum)='\0';
	fclose(infp);

	printf("%s\n",buffer);fflush(stdout);

	while(*buffer!='\0'){

		/* Read a word from buffer to tmp.*/
		while(*buffer!=' ' && *buffer!='\0'){
			tmp[n++]=*buffer++;
			if(n>7){
				tmp[7]='\0';
				printf(" %s : Bad MorseCode!\n", tmp);
				exit(1);
			}
		}
		tmp[n]='\0';
		n=0; 
		printf("%s\t",tmp);fflush(stdout);
		

		while(strcmp(tmp,table[i++].mor)){
			if(i>=MAX && *(buffer+1)!='\0'){
				printf(" %s : CANNOT find it!\n", tmp);
				exit(1);
			}
		}

		fputc(table[--i].letter,outfp);
		printf("%c\t",table[i].letter);fflush(stdout);
		i=0;
		buffer++;
	}
	fclose(outfp);
	printf("The translated file is created.\n");
	fflush(stdout);
}

void t2m()
{
	char *buffer;
	int fnum,i=0;

	/* Read all of the data from srcfile to buffer.*/
	fnum=file_size(infp);

	buffer=make_buf(fnum+1);
	if((fread(buffer,sizeof(char),fnum,infp))!=fnum){
		printf("\nSomething wrong about reading file!\n");
		exit(1);
	}
	*(buffer+fnum)='\0';
	fclose(infp);

	printf("%s %d\n", buffer,(int)(*buffer));fflush(stdout);

	while(*buffer!='\0'){
		/* find the MorseCode according to character.*/
		while(*buffer!=table[i].letter){
			
			i++;
			fflush(stdout);
			if(i>MAX && *buffer!=EOF){
				printf(" %c %d: Bad character\n", *buffer,(int)(*buffer));
				exit(1);
			}
		}
		buffer++;
		printf("%c-->%s\t\n",table[i].letter,table[i].mor);fflush(stdout);

		fputs(table[i].mor,outfp);
		fputc(' ',outfp);
		i=0;
	}
	fclose(outfp);
	printf("The translated file is created.\n");
	fflush(stdout);
}

int main(int argc,char *argv[])
{
	if (argc!=4){
		printf("Usage: trans [-R/-S] srcfile outfile\n");
		printf("\n\t -r translate Morse to English.");
		printf("\n\t -s translate English to Morse.");
		printf("\n\t -h show this help information.\n");
		fflush(stdout);
		return 1;
	}

	if (!strcmp(argv[1],"-r") || !strcmp(argv[1],"-R")){
		check_file(argv[2],argv[3]);
		m2t();
	}
	else if (!strcmp(argv[1],"-s") || !strcmp(argv[1],"-S")){
		check_file(argv[2],argv[3]);
		t2m();
	}else{
		printf("You input wrong arguments!\n");
		printf("Please type \"trans -h\".\n");
		fflush(stdout);
	}
	return 0;
}
Dec 16

公布期末设计Smallshell的完整源代码:

 

/* *************************************************
 *
 *          Small shell on Unix/Linux
 *
 *   This shell finished all the functions which 
 *   are required. And I added new inner functions
 *   "help" and "exit" by myself.
 *  
 *   Enjoy it!
 *
 *   author: Longqianzhi 용성지 
 *   Stu_ID: 12094817
 *   data:   Dec/27/2010
 *
 * *************************************************/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

#define MAX_CMD_ARG 10
#define MAX_CMD_LIST 10

const char *prompt = "# ";

char* cmdlist[MAX_CMD_LIST];
char* cmdargs[MAX_CMD_ARG];
char  cmdline[BUFSIZ];

void fatal(char *str);
void execute_cmd(char *cmd);
void execute_cmdline(char* cmdline);
int makeargv(char *s, const char *delimiters, 
	             char** argvp, int MAX_LIST);
void help();
void cd(char *path);
void catchint(int);
void join();                    /* Use one pipe to communication.*/
int join2();                    /* Use two pipe to communication.*/
int dpipe_test();               /* It's useless.Just for test.*/
void parse_filter(char *cmd);   /* A filter for argument*/ 


int main(int argc, char**argv){
	int i=0;
	static struct sigaction act;

	/*Cope with the signal*/

	act.sa_handler=catchint;
	sigfillset(&(act.sa_mask));
	sigaction(SIGINT,&act,NULL);
	sigaction(SIGQUIT,&act,NULL);

	while (1) {     
		fputs(prompt, stdout);
		fgets(cmdline, BUFSIZ, stdin);
		cmdline[ strlen(cmdline) -1] ='\0';

		execute_cmdline(cmdline);
		printf("\n");
	}
	return 0;
}

void fatal(char *str){
	perror(str);
	exit(1);
}

void execute_cmdline(char* cmdline){
	int count = 0;
	int i=0;
	count = makeargv(cmdline, "!", cmdlist, MAX_CMD_LIST);

    /* Execute the commands with different way.*/   

	/*Just a single command.*/
	if(count==1){
	
		/* First of all,try to make sure whether
		 * the command is "cd".
		 */
		if(cmdlist[0][0]=='c'&&cmdlist[0][1]=='d'){
			parse_filter(cmdlist[0]);  
			count = makeargv(cmdlist[0], " \t", cmdargs, MAX_CMD_ARG);
			if(!strcmp("cd",cmdargs[0])){
				if(chdir(cmdargs[1]))  fatal("cd");
				return;
			}
		}
	
		/* Fork a child process to run every
		 * commands except "cd" 
		*/
		 
		switch(fork())
		{
		case -1: fatal("fork error");
		case  0: execute_cmd(cmdlist[0]);
		default:
			wait(NULL);
			fflush(stdout);
		}
	}
	
	/*Execute two programs with a pipe.*/
	if(count==2){
		join();
	}

	/*Execute three programs with two pipes.*/
	if(count==3){
		join2();
	}

	/*There are too many commands*/
	if(count>=4){
		printf("Too many pipes!\n");
		return;
	}
}

/* *****************************************
 * Execute a single commands with arguments.
 *
 * *****************************************/
void execute_cmd(char *cmd){
	int i=0; 
	int count = 0;
	
	parse_filter(cmd);  
	count = makeargv(cmd, " \t", cmdargs, MAX_CMD_ARG);

	/* 
	 * Recognize some inner functions 
	 * like cd,help,exit and so on.
	 * Also you can add some new inner
	 * functions by yourself here.
	 *
	 */
	if(!strcmp("help",cmdargs[0])){
		help();
		return ;
	}

	if(!strcmp("exit",cmdargs[0])){
		kill(getppid(),SIGKILL); /*kill parent process*/
		raise(SIGKILL); /*kill myself*/
		exit(0);
	}

	execvp(cmdargs[0], cmdargs);
	fatal("exec error");
}

/* *****************************************
 *  Count the arguments'number in a command.
 *
 * ***************************************/
int makeargv(char *s, const char *delimiters, 
   					char** argvp, int MAX_LIST) {

	int i = 0;
	int numtokens = 0;
	char *snew = NULL;

	if( (s==NULL) || (delimiters==NULL) ) return -1;

	snew = s + strspn(s, delimiters);	
	if( (argvp[numtokens]=strtok(snew, delimiters)) == NULL )
	return numtokens;
	
	numtokens = 1;
	while(1){
		if( (argvp[numtokens]=strtok(NULL, delimiters)) == NULL)
			break;
		if(numtokens == (MAX_LIST-1)) return -1;
			numtokens++;
	}
	return numtokens;
}

/* *********************************
 * Inner fnuction: help().
 * Show some infomations to the stdin
 *
 ***********************************/
void help(){
	printf("\n  * *************************************** *");
	printf("\n  *                                         *");
	printf("\n  *         WELCOME TO SMALL SHELL !        *");
	printf("\n  *                                         *");
	printf("\n  * *************************************** *");
	printf("\n  *                                         *");
	printf("\n  *  There are 3 inner functions in shell.  *");
	printf("\n  *                                         *");
	printf("\n  *  1) cd :Change the current directory.   *");
	printf("\n  *  2) exit :Quit from the small shell.    *");
	printf("\n  *  3) help :Show this message for help.   *"); 
	printf("\n  *                                         *");
	printf("\n  *        IF YOU FIND ANY BUGS OR          *");
	printf("\n  *          HAVE ANY QUESTIONS             *");
	printf("\n  *                                         *");
	printf("\n  *    mail to me:longqianzhi@gmail.com     *");
	printf("\n  *                                         *");
	printf("\n  * *************************************** *\n");
	exit(0);
}


/* ***************************
 * Inner function:cd().
 * Change the current directory.
 *
 * ***************************/
 
void cd(char *path){
	if(chdir(path))
		fatal("cd");
}


/* ************************************
 * The function about act.sa_handler
 * If press the Ctrl+c, resume the shell.
 *
 * ************************************/
 
void catchint(int signo){
	printf("\nReceive a signo=%d\n",signo);
	printf("Returning to the shell\n");

	/* Init the cmdline Array.
	 * If not,the shell will try to run 
	 * commands in the memory.
	 */
	cmdline[0]='\0';
}


/* ************************************
 * An easy way to use double pipe.
 *
 * But this function is just for test and   
 * debug in the project,because I wrote  
 * a new one by myself. The new one is 
 * called "join2".
 *
 * ***********************************/

int dpipe_test(){

	/*build command string with normal format.*/

	char newstr[128];
	strcpy(newstr,cmdlist[0]);
	strcat(newstr,"|");
	strcat(newstr,cmdlist[1]);
	strcat(newstr,"|");
	strcat(newstr,cmdlist[2]);
	
	/*call system shell to run the commmands*/
	system(newstr);
	return 0;
}


/* **************************************
 * Delete special character from argument.
 * If there is any special charater,
 * this function will change them to '\32'
 *
 * ***************************************/
 
void parse_filter(char *cmd){
	int i=0;
	int CMAX=strlen(cmd);
	
	while(cmd[i]!=' '&&i<CMAX) i++;
	
	if((++i)<CMAX){
		if (cmd[i++]=='-')	{	
			while(cmd[i]!=' '&&i<CMAX){
			
				if(cmd[i]<'0'||(cmd[i]>'9'&&cmd[i]<'A')||
					(cmd[i]>'Z'&&cmd[i]<'a')||cmd[i]>'z'){

					char tmp=cmd[i-1];			
					cmd[i]=tmp;	
				}
				i++;
			}
		}
	}
	
}

/* ***********************************
 * Link the child process's stdout to
 * grandchild process's stdin with pipe.
 *
 * ***********************************/
 
void join(){
	int p[2],status;

	switch (fork()){
		case -1:fatal("1st fork call in join()");
		case 0:break;
		default:wait(&status);
				return;
	}
	
	/* Try to make a new pipe.*/
	if(pipe(p)==-1) fatal("pipe call in join()");

	switch(fork()){
		case -1:fatal("2nd fork call in join()");
		case 0:
				dup2(p[1],1);
				close(p[0]);
				close(p[1]);
				execute_cmd(cmdlist[0]);
				fatal("1st execvp call in join()");
		default:
				dup2(p[0],0);
				close(p[0]);
				close(p[1]);
				execute_cmd(cmdlist[1]);
				fatal("2nd execvp call in join()");
	}
}



/* *************************************
 * Link three child/grandchild processes 
 * one by one with two pipes.
 *
 * ************************************/

int join2(){
	int status,p1[2],p2[2];
	
	/*Test the double pipe.*/	
	if(dpipe_test()==0) return 0;  

	/* Grandparent process */
	switch(fork()){
		case -1:fatal("1st fork call");
		case 0:break;
		default:
			   wait(&status);
			   return status;
	}


	/* Parent process.Run the last command.*/

	if(pipe(p1)<0) fatal ("pipe call"); /*make a pipe.*/

	switch(fork()){
		case -1:fatal("2nd fork call");
		case 0:break;
		default:
			   dup2(p1[0],0);
			   close(p1[0]);
			   close(p1[1]);

			   execute_cmd(cmdlist[2]);
			   fatal("1st exec call");
	}
	
	/* Try to make a new pipe.*/

	if(pipe(p2)<0) fatal("pipe call"); 

	/* Child process.Run the second command.*/
	
	switch(fork()){
		case -1:fatal("3th fork call");
		case 0:break;
		default:
			   dup2(p1[1],1);
			   dup2(p2[0],0);
			   close(p1[0]);
			   close(p1[1]);
			   close(p2[0]);
			   close(p2[1]);

			   execute_cmd(cmdlist[1]);
			   fatal("2nd exec call");
	}

	/* Grandchild process.Run the first command.*/
	
	dup2(p2[1],1);
	close(p2[0]);
	close(p2[1]);

	execute_cmd(cmdlist[0]);
	fatal("3th exec call");

}

 

Jul 16

    DOS下虽然有edit编辑器和更加原始的EDLIN行编辑器,但近几天我把《THE CRAFT OF C》中关于Screen-Editor的代码全部输机,想自己再弄出个新的文本编辑器。

代码如下:(在turboc下成功编译通过,但无法正常运行)

/* A Screen Editor Subsystem*/

#define TURBOC

#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <bios.h>
#include <conio.h>

#define BUF_SIZE 32000
#define LINE_LEN 79
#define MAX_LINES 24
#define KILL_BUF_SIZE 4*LINE_LEN
char buf[BUF_SIZE];
char *curloc,*endloc;
int scrnx,scrny;
char killbuf[KILL_BUF_SIZE];

char *helpline=
    "F1:save  F2:load  F3:find  F4:replace\
    ^K:Kill line  ^Y:Yank  ^Z:Quit ";

void edit(char *fname),help();
void gotoxy(int x,int y),clrline(int y);
void edit_clr_eol(int x,int y),clrscr();
void printline(char *p),delete_char(void);
void search(),kill_line();
void upline();
void downline(),left(),right();
void scrolldn (int x,int y);
void scrollup(int topx,int topy,int endx,int endy);
void display_scrn(int x,int y,char *p);
void pagedown(),pageup(),replace();
void home(),gotoend(),yank();
int load(char *fname),save(char *fname);
void edit_gets(char *str);

main(int argc,char *argv[])
{
    if (argc==2) edit(argv[1]);
    clrscr();
    return 0;
}

/*  This is the editor's entry function and contains
    its main loop.

    Call it with the name of the file you want to edit.
*/

void edit(char *fname)
{
    union k{
        char ch[2];
        unsigned i;
    }key;
    char name[80];

    /*try to load the file*/
    if(!load(fname)) curloc=endloc=buf;
    strcpy(name,fname);

    clrscr();

    scrnx=scrny=0;

    display_scrn(0,0,curloc);
    help();
    gotoxy(0,0);

    /*Editor main loop*/
    do{
        key.i=bioskey(0);
        if(!key.ch[0]){
            switch(key.ch[1]){
                case 59: /*F1 save*/
                    save (name);
                    break;
                case 60: /*F2 load*/
                    clrline(MAX_LINES);
                    gotoxy(0,MAX_LINES);
                    printf ("Enter filename:");
                    edit_gets(name);
                    if (*name) load (name);
                    help();
                    display_scrn(0,0,curloc);
                    scrnx=scrny=0;
                    break;
                case 61: /*F3 search*/
                    search();
                    break;
                case 62: /*F4 relace*/
                    replace();
                    break;
                case 71: /*home*/
                    home();
                    break;
                case 79: /*end*/
                    gotoend();
                    break;
                case 75: /* left*/
                    left();
                    break;
                case 77: /*right*/
                    right();
                    break;
                case 72: /*up*/
                    upline();
                    break;
                case 80: /*down*/
                    downline();
                    break;
                case 73: /*page up*/
                    pageup();
                    break;
                case 81: /*page down*/
                    pagedown();
                    break;
                case 83: /*del*/
                    if(curloc<endloc) delete_char();
                    break;
            }
	    if(curloc<buf){
		scrnx=scrny=0;
                curloc=buf;
            }
            gotoxy(scrnx,scrny);
        }
        else{   /* enter keystroke into file*/
            switch(key.ch[0]){
                case '\r': /* Carriage return*/
                    /*see if buffer is full*/
                    if(endloc==buf+BUF_SIZE-2) break;

                    /* move contents of file below current
                       location down one byte to make room
                       for the RETURN
                    */
                    memmove(curloc+1,curloc,endloc-curloc+1);

                    *curloc=key.ch[0];
                    curloc++;

                    /*clear rest of line*/
                    edit_clr_eol(scrnx,scrny);
                    scrnx=0;
                    scrny++;

                    /*move text on the screen down*/
                    if (scrny==MAX_LINES){
                        scrny=MAX_LINES-1;
                        scrollup(0,0,LINE_LEN,scrny);
                    }
                    else scrolldn(scrnx,scrny);

                    gotoxy(scrnx,scrny);
                    printline(curloc);
                    endloc++;
                    break;

                case '\b': /*backspace*/
                    if(curloc==buf) break;
                    left ();
                    delete_char();
                    break;

                case 11: /*C-K:kiil line*/
                    kill_line();
                    break;
		case 25: /*C-Y:yank kill buffer*/
                    yank();
                    break;
                default:
                    if(endloc==buf+BUF_SIZE-2) break;

                    /*can't type past end of line*/
                    if(scrnx==LINE_LEN) break;
                    memmove(curloc+1,curloc,endloc-curloc+1);
                    *curloc=key.ch[0];
                    putch(*curloc);
                    scrnx++;
                    gotoxy(scrnx,scrny);
                    printline(curloc+1);
                    curloc++;
                    endloc++;
            }
            gotoxy(scrnx,scrny);
        }
    }while(key.ch[0]!=26);
}


/* Display a line pointed to by P.*/
void printline(register char *p)
{
    register int i;
    i=scrnx;
    while(*p!='\r'&& *p && i<LINE_LEN){
        putch(*p);
        p++;
        i++;
    }
}

/*Insert previously killed line*/
void yank()
{
    char *p;

    p=killbuf;
    while(*p){
        memmove(curloc+1,curloc,endloc-curloc+1);
        *curloc=*p;
        if(scrnx<LINE_LEN){
            putch(*curloc);
            scrnx++;
        }
        curloc++;
        endloc++;
        p++;
    }
    printline (curloc);
}

/*Delete the line at the current location*/
void kill_line()
{
    register int i;
    char *p,*killbufptr;
    if(*curloc=='\r'){
        delete_char();
        return;
    }

    edit_clr_eol(scrnx,scrny);

    /*find out how many characters are in the line*/
    p=curloc;
    i=0;
    killbufptr=killbuf;
    while(*p!='\r' && p<endloc){
        i++;
        *killbufptr=*p;
        p++;
        if(killbufptr<killbuf+KILL_BUF_SIZE-2) killbufptr++;
    }
    *killbufptr='\0';

    /*remove the line*/
    memmove(curloc,curloc+1,endloc-curloc);
    endloc-=i;
}


/*Global search and replace*/
void replace()
{
    register int len1;
    char str1[80],str2[80];
    char *p,*p2;

    clrline(MAX_LINES);
    gotoxy(0,MAX_LINES);
    printf("enter string to replace: ");
    edit_gets(str1);

    clrline(MAX_LINES);
    gotoxy(0,MAX_LINES);
    printf ("enter replacement: ");
    edit_gets(str2);

    p=curloc;
    len1=strlen(str1);

    while(*str1){
        /*search for a string*/
	while(*p && strncmp(str1,p,len1)) p++;
        if (!p) break;

        /*remove old string*/
        memmove(p,p+len1,endloc-p);
        endloc-=len1;

        /*insert new string*/
        p2=str2;
        while(*p2){
            memmove(p+1,p,endloc-p+1);
            *p=*p2;
            p++;
            endloc++;
            p2++;
        }
    }
    clrscr();

    /*find location of top of screen*/
    p=curloc;
    for(len1=scrny;len1>=0&&p>buf;){
        p--;
        if(*p=='\r') len1--;
    }
    if(*p=='\r') p++;

    /*redisplay current screen*/
    display_scrn(0,0,p);
    help();
}


/*Delete character at the current location.*/
void delete_char()
{
    gotoxy(scrnx,scrny);
    if(*curloc=='\r'){
        scrollup(0,scrny+1,LINE_LEN,MAX_LINES-1);
        memmove(curloc,curloc+1,endloc-curloc);
        endloc--;
        display_scrn(scrnx,scrny,curloc);
        help();
    }
    else{
        memmove(curloc,curloc+1,endloc-curloc);
        endloc--;
	printline(curloc); printf(" ");
    }
}


/*Display help line*/
void help()
{
    gotoxy(0,MAX_LINES);
    printf(helpline);
}

/*Move current location left*/
void left()
{
    if(curloc==buf) return;
    scrnx--;
    if(scrnx<0){
        scrnx=0;
        upline();
        /*find end of line*/
        while(*curloc!='\r'){
            curloc++;
            scrnx++;
        }
    }
    else curloc--;
}


/*Move currrent position right*/
void right()
{
    /*can't move rihgt*/
    if(curloc+1>endloc) return;

    scrnx++;

    /*if at end of line,go to next one*/
    if(scrnx>LINE_LEN||*curloc=='\r'){
        scrnx=0;
        scrny++;
        if(scrny==MAX_LINES){
            scrny=MAX_LINES-1;
            downline();

            /*move cursor and current loc to start
             of new line*/
            curloc--;
            while(*curloc!='\r') curloc--;
            curloc++;
            scrnx=0;
        }
        else curloc++;
    }
    else curloc++;
}

/*Find a string*/
void search()
{
    char str[80];
    register char *p;
    int len,i;

    clrline(MAX_LINES);
    gotoxy(0,MAX_LINES);
    printf("search string: ");
    edit_gets(str);
    if(!*str) return;

    p=curloc;
    len=strlen(str);

    /*search for the string*/
    while(*p && strncmp(str,p,len)) p++;
    if(!*p) return;

    /*back up to start of line*/
    i=0;
    while(p>buf&&*p!='\r'){
        p--;
        i++;
    }
    p++;
    i--;

    /*reposition current location to start of match*/
    curloc=p+i;
    scrnx=i;
    scrny=0;

    /*diplay screenof text at location of match*/
    clrscr();
    display_scrn(0,0,p);
    help();
}

/*Move up one line.*/
void upline()
{
    register int i;
    char *p;
    if(curloc==buf) return;

    p=curloc;

    if(*p=='\r') p--;

    /*back up loacator to start of current line.*/
    for(;*p!='\r'&&p>buf;p--);
    if(*p!='\r') return;
    curloc=p;
    curloc--;
    i=scrnx;

    /*find start of next line*/
    while(*curloc!='\r' && curloc>=buf) curloc--;
    scrny--;scrnx=0;
    curloc++;

    /*at top of screen,must scroll up*/
    if(scrny<0){
        scrolldn(0,0);
        scrny=0;
        gotoxy(0,0);
        printline(curloc);
    }

    /* position the cursor and current location at
     same scrnx position as previous line if possible*/
    while(i&& *curloc!='\r'){
        curloc++;
        scrnx++;
        i--;
    }
}


/* Move down one line. */
void downline()
{
    register int i;
    char *p;
    i=scrnx;
    p=curloc;

    /* advance current location to start to next line*/
    while(*p!='\r' && p<endloc) p++;
    if(p==endloc) return;
    p++;
    curloc=p;
    scrny++;scrnx=0;

    /*if moving down past the bottom of the screen*/
    if(scrny==MAX_LINES){
        scrny=MAX_LINES-1;
        scrollup(0,0,LINE_LEN,MAX_LINES-1);
        gotoxy(scrnx,scrny);
        printline(curloc);
    }

    /* advance to corresponding character in next line*/
    while(i && *curloc!='\r' && curloc<endloc){
        curloc++;
        scrnx++;
        i--;
    }
}


/* Display a screen full of text(up to 24lines)
   starting at the specified location.
*/
void display_scrn(int x,int y,char *p)
{
    register int i;
    gotoxy(x,y);

    i=0;
    while(y<MAX_LINES && *p){
        switch(*p){
            case '\r':printf("\n");
                y++;
                i=0;
                break;
            default:if(i<LINE_LEN) putch(*p);
                i++;
        }
        p++;
    }
}


/* Page down MAX_LINES lines.*/
void pagedown()
{
    register int i;

    clrscr();

    /*count down MAX_LINES lines.*/
    for(i=0;i<MAX_LINES && curloc<endloc;){
        if (*curloc=='\r') i++;
        curloc++;
    }
    help();
    scrnx=0;scrny=0;
    display_scrn(0,0,curloc);
}

/* Page up MAX_LINES lines*/
void pageup()
{
    register int i;

    clrscr();
    if (*curloc=='\r' && curloc>buf) curloc--;

    /* go back MAX_LINES in buffer*/
    for(i=0;i<MAX_LINES+1 && curloc>buf;){
        if(*curloc=='\r') i++;
        curloc--;
    }
    if(i==MAX_LINES+1) curloc+=2;

    help();
    scrnx=0;scrny=0;
    display_scrn(0,0,curloc);
}


/* Go to the top of the file.*/
void home()
{
    clrscr();
    curloc=buf;
    scrnx=scrny=0;
    display_scrn(0,0,curloc);
    help();
}

/*  Go to the end of the file. */
void gotoend()
{
    clrscr();
    curloc=endloc;
    pageup();
}

/* Load a file.*/
load(char *fname)
{
    FILE *fp;
    char ch,*p;

    if((fp=fopen(fname,"rb"))==NULL)
        return 0;

    p=buf;
    while(!feof(fp) && p!=buf+BUF_SIZE-2){
        ch=getc(fp);
        if(ch!='\n' && ch!=EOF){
	    *p=ch;
            p++;
        }
    }
    *p='\0';
    fclose (fp);
    curloc=buf;
    endloc=p;
    return 1;
}

/* Save a file.*/
save(char *fname)
{
    FILE *fp;
    char *p,name[80];

    if(!*fname){
        printf("filename: ");
        gets(name);
    }
    else strcpy(name,fname);

    if((fp=fopen(name,"wb"))==NULL)
        return 0;

    p=buf;
    while(p!=endloc){
        if(*p!='\r')
            putc(*p,fp);
        else{
            putc('\r',fp);
            putc('\n',fp);
        }
        p++;
    }
    fclose(fp);
    return 1;
}


/* Read a string from the keyboard,but do not
   scroll the display when a RETURN is entered.
*/
void edit_gets(char *str)
{
    char *p;

    p=str;

    for(;;){
        *str=getch();
        if(*str=='\r'){
            *str='\0';
            return;
        }
        if(*str=='\b'){
            if(str>p){
		str--;
		putch('\b');
		putch(' ');
		putch('\b');
            }
        }
        else{
            putch(*str);
            str++;
        }
    }
}


/* Read and save cursor coordinates.*/
void cursor_pos()
{
    union REGS i,o;
    i.h.bh=0;
    i.h.ah=3;
    int86(16,&i,&o);
}

/* Send cursor to specified X,Y (0,0 is
   Upper left corner.
*/
void gotoxy(int x,int y)
{
    union REGS i;

    i.h.dh=y;
    i.h.dl=x;
    i.h.ah=2;
    i.h.bh=0;
    int86(16,&i,&i);
}

/* Clear entire line given its Y coordinate.*/
void clrline(int y)
{
    register int i;

    gotoxy(0,y);
    for(i=0;i<LINE_LEN;i++) putch(' ');
}

/* Clear to end of specified line.*/
void edit_clr_eol(int x,int y)
{
    char *p;

    p=curloc;
    gotoxy(x,y);
    for(;x<LINE_LEN && *p!='\r' && *p;x++,p++){
        printf(" ");
    }
}

/* Clear the screen.*/
void clrscr()
{
    union REGS r;
    r.h.ah=6;
    r.h.al=0;
    r.h.ch=0;
    r.h.cl=0;
    r.h.dh=MAX_LINES;
    r.h.dl=LINE_LEN;
    r.h.bh=7;
    int86(0x10,&r,&r);
}

/*Scroll down the screen.*/
void scrolldn(int x,int y)
{
    union REGS r;

    r.h.ah=7;
    r.h.al=1;
    r.h.ch=y;
    r.h.cl=x;
    r.h.dh=MAX_LINES-1;
    r.h.dl=LINE_LEN;
    r.h.bh=7;
    int86(0x10,&r,&r);
}

/* Scroll up the screen using the specified coordinate.*/
void scrollup(int topx,int topy,int endx,int endy)
{
    union REGS r;

    r.h.ah=6;
    r.h.al=1;
    r.h.ch=topy;
    r.h.cl=topx;
    r.h.dh=endy;
    r.h.dl=endx;
    r.h.bh=7;
    int86(0x10,&r,&r);
}

Jul 11

THE LITTLE C INTERPRETER

    这一章节,将会开发C解释器的核心部分。在阅读解释器的源码之前,如果我们能理解解释器怎样运作将大有裨益。在许多方面,解释器的代码都比表达式剖析器的更容易理解,因为在概念上,解释执行C程序可以用以下算法概括起来:

while(tokens_present){
	get_next_token;
	take_appropriate_action;
}

    这段代码和表达式剖析器比起来,看起来简单得不可思议,但这确实就是解释器所作的一切!记住一件事情就是“take_appropriate_action”这一步也许需要从输入流中读取标记。

 

1)THE INTERPRETER PRESCAN(解释器预扫描)

    在解释器能够准确地执行程序之前,有少量的工作必须做。在心中设计一个解释器不是编译器的特点就是它从源程序开头开始执行,然后到源程序结尾为止。这就是传统BASIC的工作方式。无论如何,C(或任何其他的结构化语言)无法适用于这种方式。首先,所有的C的程序从main()函数开始执行。我们不要求main()在程序中必须是第 一个函数;因此,在开始执行时必须弄清main()函数在源码中的位置。(记住全局变量也许走在main()之前,所以虽然它是第一个函数,也没有必要写在第一行。)必须找到一些办法让解释器从正确的地方开始解释。

     最后为了执行速度,在程序中定义每个函数的位置以便能够尽快地调用函数。(但在技术上不是必需的。)如果这一步没有做,每次调用函数时,都将需要一个对源码的冗长的顺序查找以确定函数的入口。

    解决这些问题的方法叫做interpreter prescan(解释器预扫描)。扫描器(有时也被称作预处理程序)被所有的商业解释器所使用,无论何种语言。在执行之前,一个预扫描器先会读取源代码,然后有些任务将优先执行。在我们的C解释器中,它将做两件重要的事:首先,寻找并标记所有永和定义函数的位置,包括main()函数;其二,寻找并分配空间给所有的全局变量。以下是预扫描部分prescan()的代码:

void prescan()
{
    char *p;
    char temp[32];
    int brace=0; /*when 0,this var tells us that
                   current source position is
                   outside of any function
                   */

    p=prog;
    func_index=0;
    do{
        while (brace){
            get_token();
            if (*token=='{') brace++;
            if (*token=='}') brace--;
        }
        get_token();

        if (tok==CHAR||tok==INT){
            putback();
            decl_global();
        }
        else if (token_type==IDENTIFIER){
            strcpy(temp,token);
            get_token();
            if (*token=='('){
                func_table[func_index].loc=prog;
                strcpy(func_table[func_index].func_name,temp);
                func_index++;
                while (*prog!=')') prog++;
                prog++;
            }
            else putback();
        }
        else if (*token=='{') brace++;
    }while(tok!=FINISHED);
    prog=p;
}

        prescan()函数时这样工作的。每次遇到开口大括号“{”时,brace就增加。当读到闭口大括号“}”时,brace就减少。因此,只要brace大于零,当前的标记就会从函数中被读入。然而如果当找到一个变量时,brace等于零,则预扫描器就会知道它一定是全局变量。同理,如果找到一个函数名且brace等于0时,那么它一定是函数的定义。

         全局变量被decl_global()储存在一个叫做global_vars的全局变量表里,代码如下:

/*
    An array of these structures will hold the info
    associated with global variables
*/
struct var_type {
    char var_name[ID_LEN];
    int var_type;
    int value;
} global_vars[NUM_GLOBAL_VARS];

int gvar_index; /*index into global variable table*/

/*Declare a global variable*/
void decl_global()
{
    get_token();
    global_vars[gvar_index].var_type=tok;
    global_vars[gvar_index].value=0;

    do{
        get_token();
        strcpy(global_vars[gvar_index].var_name,token);
        get_token();
        gvar_index++;
    }while (*token==',');
    if (*token!=';') sntx_err(SEMI_EXPECTED);
}

    整数型的变量gvar_index将在数组中存入下一个要素的空余位置。每次用户自定义函数的位置将被放入func_table数组中,代码如下:

struct func_type {
    char func_name[ID_LEN];
    char *loc;  /*location of entry point in file*/
} func_table[NUM_FUNC];

int func_index; /*index into function table*/

   2)The main() Function

    main()函数是如此工作的:载入源代码,全局变量初始化,调用prescan(),让解释器为调用main()“做好准备”,然后执行call(),代码如下:

int main(int argc,char *argv[])
{
    if(argc!=2){
        printf("usage:littlec <filename>\n");
        exit (1);
    }

    /*allocate memory for the program*/
    if ((p_buf=(char *) malloc(PROG_SIZE))==NULL){
        printf ("allocation failure");
        exit (1);
    }

    /*load the program to execute*/
    if (!load_program(p_buf,argv[1])) exit(1);
    if (setjmp(e_buf)) exit(1);

    /*set program pointer to start of program buffer*/
    prog=p_buf;
    prescan ();
    gvar_index=0;
    lvartos=0;
    functos=0;

    /*setup call to main()*/
    prog=find_func("main");
    prog--;
    strcpy(token,"main");
    call();
    return 0;
}

 
3)The interp_block() Function

    interp_block()函数时解释器的核心。这个函数将基于输入流中的下一个标记来决定采取什么动作。这个函数被设计成解释一个程序块然后再返回。如果“程序块(block)”由单个的语句组成,这个语句将被执行然后函数返回。代码如下:

/*
  Interpret a single statement or block of code.
  When interp_block() returns from its initial call,
  the final brace (or a return in main() has been encountered.
*/
void interp_block()
{
    int value;
    char block=0;

    do {
        token_type=get_token();

        /*see what kind of token is up*/
        if (token_type==IDENTIFIER) {
            putback ();
            eval_exp(&value);
            if (*token!=';') sntx_err(SEMI_EXPECTED);
        }
        else if(token_type==BLOCK){
            if (*token=='{')
                block=1;
            else return;
        }
        else
            switch (tok){
                case CHAR:
                case INT:
                    putback();
                    decl_local();
                    break;
                case RETURN:
                    func_ret();
                    return;
                case IF:
                    exec_if();
                    break;
                case ELSE:
                    find_eob();
                    break;
                case WHILE:
                    exec_while();
                    break;
                case DO:
                    exec_do();
                    break;
                case FOR:
                    exec_for();
                    break;
                case END:
                    exit(0);
            }
    } while (tok!=FINISHED&&block);
}

    除了调用像exit()的函数,当main()里遇见最后一个大括号时,C程序也将结束。这就是interp_block()函数只执行一句或一块代码,而不是整个程序的原因。

Jul 8

THE LITTLE C INTERPRETER

表达式剖析器(THE EXPRESSION PARSER)

   读取和分析表达式的这部分代码叫做表达式剖析器。毫无疑问,表达式剖析器是C解释器中单一的最重要的部分。因为C语言定义表达式的方式比其他语言更加粗鄙,所以用大量的代码组成的C源文件来实现表达式剖析器。

   有几种不同的方式来设计C的表达式剖析器。许多商业的编译器用一种由parser-generator创建的table-driven parser。尽管table-driven parser一般来说要快过其他方式,但却很难手工构建。为了开发简易的C解释器,在这里我们使用递归-继承剖析器(recursive-descent parser.)
  
   一个递归-继承剖析器本质上是一大堆处理表达式的互相递归的函数。如果是在编译器里,那么剖析器将被用来生成与源码相符的标准的目标代码。无论如何,在解释器中,剖析器的目的就是对给定的表达式求值。
  
将源代码变成他们的组成元素
 
   所有解释器的基础是一个读取源码然后返回下一个逻辑符号的特殊的函数。基于历史原因,这些逻辑标记一般与标记(token)相关联。一般而言,计算机语言,特别是C语言,依据标记来定义程序。你可以想象标记是一个不可见的程序单元。比如说,相等运算符==就是一个标记。这两个等于号分开后意义将彻底改变。同理,if 也是一个标记。在C语言中无论是i还是f都没有其他意思。
  
   在ANSI C标准中,标记被定义为属于下列几组:
   keywords    identifiers    constants   
   strings    operators    pinctuation
  
   keywords(关键字)是那些如while的构成C语言的标记。Identifier(识别符)是变量、函数、用户定义类型的名字。而Constants(常量)和 Strings(字符串)是不解自明的,就像operators(运算符)一样。最后Punctuation(标点符号)包括了几个项目,像分号,逗号,大括号,小括号等。
  
   在简易C解释器中,这个被称作get_token()的函数可以从源码中读取标记。

 

/*Get a token*/
get_token()
{
    register char *temp;
    token_type=0;tok=0;
    temp=token;
    *temp='\0';

    /* skip over white space*/
    while(iswhite(*prog)&&*prog)
        ++prog;

    if (*prog=='\r')
    {
        ++prog;
        ++prog;
        while (iswhite(*prog)&&*prog)
            ++prog;
    }

    if (*prog=='\0')
    {
        *token='\0';
        tok=FINISHED;
        return (token_type=DELIMITER);
    }

    if (strchr("{}",*prog))
    {
        *temp=*prog;
        temp++;
        *temp='\0';
        prog++;
        return (token_type=BLOCK);
    }

    /* look for comments*/
    if (*prog=='/')
        if (*(prog+1)=='*')
        {
            prog+=2;
            do
            {
                while(*prog!='*') prog++;
                prog++;
            }while (*prog!='/');
            prog++;
        }

    if (strchr("!<>=",*prog))
    {
        switch (*prog)
        {
            case '=':
                if (*(prog+1)=='=')
                {
                    prog++;prog++;
                    *temp=EQ;
                    temp++; *temp=EQ; temp++;
                    *temp='\0';
                }
                break;
            case '!':
                if (*(prog+1)=='=')
                {
                    prog++;prog++;
                    *temp=NE;
                    temp++; *temp=NE; temp++;
                    *temp='\0';
                }
                break;
            case '<':
                if (*(prog+1)=='=')
                {
                    prog++;prog++;
                    *temp=LE;temp++;*temp=LE;
                }
                else
                {
                    prog++;
                    *temp=LT;
                }
                temp++;
                *temp='\0';
                break;
            case '>':
                if (*(prog+1)=='=')
                {
                    prog++;prog++;
                    *temp=GE;temp++;*temp=GE;
                }
                else
                {
                    prog++;
                    *temp=GT;
                }
                temp++;
                *temp='\0';
                break;
        }
        if (*token) return(token_type=DELIMITER);
    }

    if (strchr("+-*^/%=;(),'",*prog))
    {
        *temp=*prog;
        prog++;
        temp++;
        *temp='\0';
        return (token_type=DELIMITER);
    }

    if (*prog=='"')
    {
        prog++;
        while (*prog!='"' && *prog!='\r')
            *temp++=*prog++;
        if (*prog=='\r') sntx_err(SYNTAX);
        prog++;*temp='\0';
        return (token_type=STRING);
    }

    if (isdigit(*prog))
    {
        while(!isdelim(*prog))
            *temp++=*prog++;
        *temp='\0';
        return(token_type=NUMBER);
    }

    if(isalpha(*prog))
    {
        while (!isdelim(*prog))
            *temp++=*prog++;
        token_type=TEMP;
    }

    *temp='\0';

    /*see if a string is a command or variable*/
    if (token_type==TEMP)
    {
        tok=look_up(token);
        if(tok) token_type=KEYWORD;
        else token_type=IDENTIFIER;
    }
    return token_type;
}

get_token()函数用到了以下的全局变量和枚举类型:

 

extern char *prog;
extern char *p_buf;
extern char token[80];
extern char token_type;
extern char tok;


enum tok_types {DELIMITER,IDENTIFIER,NUMBER,
                KEYWORD,TEMP,STRING,BLOCK};
				
enum double_ops {LT=1,LE,GT,GE,EQ,NE};

enum error_msg{
    SYNTAX,UNBAL_PARENS,NO_EXP,EQUALS_EXPECTED,
    NOT_VAR,PARAM_ERR,SEMI_EXPECTED,
    UNBAL_BRACES,FUNC_UNDEF,TYPE_EXPECTED,
    NEST_FUNC,RET_NOCALL,PAREN_EXPECTED,
    WHILE_EXPECTED,QUOTE_EXPECTED,NOT_TEMP,
    TOO_MANY_LVARS};

   在源码中当前位置由prog指定。p_buf指针无法被解释器所改变而且经常指向正在被解析的程序的开头。get_token()函数开始跳过所有的空白,包括回车和空行。直到没有C标记包含空格,所以的空格必须被跳过。当然get_token()函数也要跳过注释。接下来,将每个标记的字符串表现形式归类到token,它的类型用token_type表达,而且,如果标记是一个关键字,它的内部表示将通过look_up()函数分配给tok。如你所见的get_token()函数,它将C的双字关系运算符转换成对应的枚举值。虽然不是技术需要,但这一步可以简化parser剖析器的实现。最后,如果parser剖析器遇到语法错误,将会调用sntx_err()函数。sntx_err()函数如下:
   

 

/*Display an error message*/
void sntx_err(int error)
{
    char *p,*temp;
    int linecount=0;
    register int i;

    static char *e[]={
        "Syntax error",
        "unbalanced parentheses",
        "no expression present",
        "equals sign expected",
        "not a variable",
        "parameter error",
        "semicolon expected",
        "unbalanced braces",
        "function undefined",
        "type specifier expected",
        "too many nested function calls",
        "return without call",
        "parentheses expected",
        "while expected",
        "closing quoto expected",
        "not a string",
        "too many local variable"
    };
    printf ("%s",e[error]);
    p=p_buf;
    while (p!=prog)
    {
        p++;
        if (*p=='\r')
            linecount++;
    }
    printf (" in line %d\n",linecount);
    temp=p;
    for (i=0;i<20 && p>p_buf && *p!='\n';i++,p--);
    for (i=0;i<30 && p<=temp;i++,p++)
        printf ("%c",*p);
    longjmp (e_buf,1);
}

   值得注意的是sntx_err()也会显示出错语句的行号,最后要注意的是sntx_err()调用longjmp()结束。因为语法错误会在嵌套或递归程序中频繁地出现,最简单的控制错误的方法就是跳到一个安全的地方。

 

   

 

Jul 7

C语言的解释器LittleC的演示代码(在细节上有别于传统的编译型C语言版本):

/* Little C demonstration Program #1.
    
    This program demonstrates all features
    of C that are recognized by Little C.
*/

int i,j; /*global vars*/
char ch;

main()
{
    int i,j;/*local vars*/
    puts("Little C Demo Program.");
    print_alpha();
    do{
        puts("enter a number (0 to quit):");
        i=getnum();
        if (i<0){
            puts("number must bepositive,try again");
        }
        else{
            for(j=0;j<1;j=j+1){
                print (j);
                print ("summed is");
                print (sum(k));
                puts("");
            }
        }
    }while(!=0);
}

/* Sum the values between 0 and num*/
sum(int num)
{
    int running_sum;
    running_sum=0;
    while(num){
        running_sum=running_sum+num;
        num=num-1;
    }
    return running_sum;
}

/*Print the alphabet*/
print_alpha()
{
    for (ch='A';ch<='Z';ch=ch+1){
        putch(ch);
    }
    puts ("");
}

/*Nested lop example*/
main ()
{
    int i,j,k;
    
    for(i=0;i<5;i=i+1){
        for(j=0;j<3;j=j+1){
            for(k=3;k;k=k-1){
                print (i);
                print (j);
                print (k);
                puts("");
            }
        }
    }
    puts("done.");
}

/*Assignments as operations..*/
main()
{
    int a,b;
    a=b=10;
    print(a);print (b);
    while(a=a-1){
        print (a);
        do{
            print(b);
        }while((b=b-1)>-10);
    }
}

/*This program demonstrates recursive functions.*/
main()
{
    print(factr(7)*2);
}
/*return the factorial of i*/
factr(int i)
{
    if(i<2){
        return i;
    }
    else{
        return i*factr(i-1);
    }
}

/*A more rigorous example of function arguments.*/
main()
{
    f2(10,f1(10,20),99);
}

f1(int a,int b)
{
    int count;
    print("in f1");
    count=a;
    do{
        print(count);
    }while(count=count-1);
    
    print(a);print(b);
    print(a*b);
    return a*b;
}
f2(int a,int x,int y)
{
    print(a);print(x);
    print(x/a);
    print(y*x);
}


/*The loop statements*/
main()
{
    int a;
    char ch;
    
    puts("Enter a number");
    a=getnum();
    while(a){
        print(a);
        print(a*a);
        puts("");
        a=a-1;
    }
    puts("enter characters,'q' to quit");
    do{
        ch=getche();
    }while(ch!=q);
    for(a=0;a<10;a=a+1){
        print(a);
    }
}
    
Jul 7

因空间有限,Little C暂只包含5个库函数,分别是:getche(),putch(),puts(),print(),getnum().

 

//
//  lclib.c
//  cinterp
//
//  Created by long on 12. 6. 16..
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

/*  Internal Library Functions */

#include <stdio.h>
#include <stdlib.h>

extern char *prog;
extern char token[80];
extern char token_type;
extern char tok;

enum token_types{
    DELIMITER, IDENTIFIER, NUMBER, COMMAND, STRING,
    QUOTE, VARIABLE, BLOCK, FUNCTION
};

/*  These are the contants used to call sntx_err() when
    a syntax error occurs. Add more if you like.

    NOTE: SYNTAX is a generic error message used when
    nothing else seems appropriate.
*/

enum error_msg{
    SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,
    NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
    UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
    NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
    WHILE_EXPECED, QUOTE_EXPECTED, NOT_TEMP,
    TOO_MANY_LVARS
};


int get_token();
void sntx_err(int error);
void eval_exp(int *result);
void putback();

/*  Get a character from console */
char call_getche()
{
    char ch;
    ch=getchar();
    while(*prog!=')')  
        prog++;
    prog++;     /* advance to end of line */
    return ch;
}

/*  Put acharacter to the display */
int call_putch()
{
    int value;
    
    eval_exp(&value);
    printf("%c",value);
    return value;
}

/*  Call puts */
int call_puts()
{
    get_token();
    if(*token!='(')
        sntx_err(PAREN_EXPECTED);
    
    get_token();
    if(token_type!=QUOTE) 
        sntx_err(QUOTE_EXPECTED);
    
    puts(token);
    get_token();
    if(*token!=')')
        sntx_err(PAREN_EXPECTED);
    
    get_token();
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
    putback();
    return 0;
    
}


/*  A built-in console output function */
int print()
{
    int i;
    get_token();
    if(*token!='(')
        sntx_err(PAREN_EXPECTED);
    get_token();
    
    if(token_type==QUOTE){
        printf("%s",token);
    }
    else{
        putback();
        eval_exp(&i);
        printf("%d",i);
    }
    
    get_token();
    
    if(*token!=')')
        sntx_err(PAREN_EXPECTED);
    
    get_token();
    
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
    putback();
    return 0;
}


/*  Read an integer from keyboard */
int getnum()
{
    char s[80];
    
    gets(s);
    while(*prog!=')')
        prog++;
    
    prog++;
    return atoi(s);
}

如用Turbo/Borland C/C++,可用以下命令编译。

tcc -c parser.c

tcc -c lclib.c

tcc littlec.c parser.obj lclib.obj

 

Jul 7

这就是简易的C解释器的主程序代码,可正确编译。

gcc littlec.c parser.o lclib.o

clang littlec.c parser.o lclib.o

//
//  littlec.c
//  cinterp
//
//  Created by long on 12. 6. 16..
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define NUM_FUNC        100
#define NUM_GLOBAL_VARS 100
#define NUM_LOCAL_VARS  200
#define NUM_BLOCK       100
#define ID_LEN          31
#define FUNC_CALLS      31
#define NUM_PARAMS      31
#define PROG_SIZE       10000
#define LOOP_NEST       31

enum tok_types {
    DELIMITER, IDENTIFIER, NUMBER, KEYWORD,
    TEMP, STRING, BLOCK
};

/* add additional C keyword tokens here */
enum tokens{
    ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE,
    SWITCH, RETURN, EOL, FINISHED, END
};

/* add additional double operators here */
enum double_ops{LT=1, LE, GT, GE, EQ, NE};


/*  These are the constants used to call sntx_err() when
 a syntax error occurs. Add more if you like.
 
 NOTE: SYNTAX is a generic error message used when 
 nothing else seems appropriate.
 */

enum error_msg{
    SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,
    NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
    UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
    NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
    WHILE_EXPECED, QUOTE_EXPECTED, NOT_TEMP,
    TOO_MANY_LVARS
};

char *prog;  /* current location in source code */
char *p_buf; /* points to start of program buffer */
jmp_buf e_buf;   /* hold environment for longjmp() */


/*  An array of these structures will hold the info
 associated with global variables.
 */
struct var_type{
    char var_name[ID_LEN];
    int var_type;
    int value;
}  global_vars[NUM_GLOBAL_VARS];

struct var_type local_var_stack[NUM_LOCAL_VARS];

/* This is the function call stack */
struct func_type{
    char func_name[ID_LEN];
    char *loc;        /* location of function entry point in file */
} func_table[NUM_FUNC];

int call_stack[NUM_FUNC];

/* Keyword lookup table */
struct commands{
    char command[20];
    char tok;
}table[]={  /* Commands must be entered lowercase */
    "if",IF,
    "else",ELSE,
    "for",FOR,
    "do",DO,
    "while",WHILE,
    "char",CHAR,
    "int",INT,
    "return",RETURN,
    
    "end",END,
    "",END
};

char token[80];
char token_type,tok;

int functos;    /* index to top of function call stack */
int func_index; /* index into function table */
int gvar_index; /* index into global variable table */
int lvartos;    /* index into  local variable stack */

int ret_value;  /* function return value */

void print();
void prescan();
void decl_global(),decl_local();
void call();
void putback();
void local_push(struct var_type i);
void eval_exp(int *value);
void sntx_err(int error);
void get_params();
void get_args();
void exec_if();
void exec_for();
void exec_do();
void exec_while();
void find_eob();
void func_push(int i);
void assign_var(char *var_name, int value);
void interp_block();
void func_ret();

int load_program(char *p,char *fname);
int find_var(char *s);
int func_pop();
int is_var(char *s);
int get_token();

char *find_func(char *name);

int main(int argc, char *argv[])
{
    if(argc!=2){
        printf ("usage: littlec <filename>\n");
        exit(1);
    }
    
    /* allocate memory for the program */
    if((p_buf=(char *) malloc(PROG_SIZE))==NULL){
        printf("allocation failure");
        exit(1);
    }
    
    /* load the program to execute */
    if( !load_program(p_buf,argv[1]))
        exit(1);
    if(setjmp(e_buf))   /* initialize long jump buffer */
        exit(1);
    
    /* set program pointer to start of the program buffer */
    prog=p_buf;
    prescan();  /* find the location of all function
                and global variables in the program */
    
    gvar_index=0;   /* initialize global variable index */
    lvartos=0;      /* initialize local variable stack index */
    functos=0;      /* initialize the CALL stack index */
    
    /* setup call to main() */
    prog=find_func("main");
    prog--;         /* abck up to opening ( */
    strcpy(token,"main");
    call();         /* call main() to start interpreting */
}

void interp_block()
{
    int value;
    char block=0;
    
    do{
        token_type=get_token();
        
        /*  If interpreting single statement, return
            on first semicolon.
         */
        
        /* see what kind of token is up */
        if(token_type==IDENTIFIER){
            /* Not a keyword, so process expression */
            putback();  /* restore token to input stream for
                         further processing by eval_exp() */
            eval_exp(&value);   /* process the expression */
            
            if (*token!=';') 
                sntx_err(SEMI_EXPECTED);
            else if(token_type==BLOCK){
                if(*token=='{')
                    block=1;    /* interpreting block, not statement */
                else return;    /* is a },so return */
            }
            else    /* is keyword */
                switch(tok){
                    case CHAR:
                    case INT:
                        putback();
                        decl_local();
                        break;
                    case RETURN:
                        func_ret();
                        return;
                    case IF:
                        exec_if();
                        break;
                    case ELSE:
                        /* find end of else block
                         and continue execution */
                        find_eob();
                        break;
                    case WHILE:
                        exec_while();
                        break;
                    case DO:
                        exec_do();
                        break;
                    case FOR:
                        exec_for();
                        break;
                    case END:
                        exit(0);
                }
        }
    } while(tok != FINISHED && block);
}
    
/* load a program. */
int load_program(char *p,char *fname)
{
    FILE *fp;
    int i=0;
        
    if((fp=fopen(fname,"rb"))==NULL)
        return 0;
    i=0;
    do{
        *p=getc(fp);
        p++;
        i++;
    } while (!feof(fp) && i<PROG_SIZE);
    *(p-2)='\0';    /* null terminate the program */
    fclose(fp);
    return 1;
}

/*  Find the location of all functions in the program
    and store global variables
 */
void prescan()
{
    char *p;
    char temp[32];
    int brace=0;    /*  when 0, this var tells us that
                        current source position is outside
                        of any function.
                     */
    p=prog;
    func_index=0;
    do{
        while(brace){
            get_token();
            if(*token=='{') brace++;
            if(*token=='}') brace--;
        }
        
        get_token();
        
        if(tok==CHAR || tok==INT){  /* is global var */
            putback();
            decl_global();
        }
        else if(token_type==IDENTIFIER){
            strcpy(temp,token);
            get_token();
            if(*token=='('){    /* must be assume a function */
                func_table[func_index].loc=prog;
                strcpy(func_table[func_index].func_name,temp);
                func_index++;
                while( *prog!= ')') prog++;
                prog++;
                /* prog points to opening curly brace of function */
            }
            else putback();
        }
        else if (*token=='{')
            brace++;
    } while(tok!=FINISHED);
        prog=p;
}

/*  Return the entry point of the specified function.
    Return NULL if not found
 */
char *find_func(char *name)
{
    register int i;
    
    for(i=0;i<func_index;i++)
        if(!strcmp(name,func_table[i].func_name))
            return func_table[i].loc;
    
    return NULL;
}

/* Declare a global variable */
void decl_global()
{
    get_token();
    
    global_vars[gvar_index].var_type=tok;
    global_vars[gvar_index].value=0;
    
    do{    /* process comma-separated list */
        get_token();    /* get name */
        strcpy(global_vars[gvar_index].var_name,token);
        get_token();
        gvar_index++;
    } while (*token != ';');
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
}

/* Declare a local variable. */
void decl_local()
{
    struct var_type i;
    get_token();
    
    i.var_type=tok;
    i.value=0;
    
    do{
        get_token();
        strcpy(i.var_name,token);
        local_push(i);
        get_token();
    } while (*token==',');
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
}

/* Call a function */
void call()
{
    char *loc,*temp;
    int lvartemp;
    
    loc=find_func(token);
    if(loc==NULL)
        sntx_err(FUNC_UNDEF);
    else{
        lvartemp=lvartos;   /* save local var stack index */
        get_args();
        temp=prog;  /* save return location */
        func_push(lvartemp);
        prog=loc;   /* reset prog to start of function */
        get_params();
        interp_block();
        prog=temp;  /* reset the program pointer */
        lvartos=func_pop();
    }
}

/*  Push the arguments to a function onto the local
    variable stack
 */
void get_args()
{
    int value,count,temp[NUM_PARAMS];
    struct var_type i;
    
    count=0;
    get_token();
    if(*token!='(')
        sntx_err(PAREN_EXPECTED);
    
    /* process a comma-separated list of values */
    do{
        eval_exp(&value);
        temp[count]=value; /* save temporarily */
        get_token();
        count++;
    } while (*token==',');
    count--;
    
    /* now, push on local_var_stack in reverse order */
    for(;count>=0;count--){
        i.value=temp[count];
        i.var_type=ARG;
        local_push(i);
    }
}

/* Get function parameters */
void get_params()
{
    struct var_type *p;
    int i;
    
    i=lvartos-1;
    do{
        get_token();
        p=&local_var_stack[i];
        
        if(*token!=')'){
            if(tok!=INT && tok!=CHAR)
                sntx_err(TYPE_EXPECTED);
            p->var_type=token_type;
            get_token();
            
            /*  link parameter name with argument 
                alreadyb on local var stack
             */
            strcpy(p->var_name,token);
            get_token();
            i--;
        }
        else break;
    } while(*token!=')');
    if(*token!=')')
        sntx_err(PAREN_EXPECTED);
}

/* Return from a function */
void func_ret()
{
    int value=0;
    
    /* get return value, if any */
    eval_exp(&value);
    
    ret_value=value;
}
           

/* Push local variable */
void local_push(struct var_type i)
{
    if(lvartos>NUM_LOCAL_VARS)
        sntx_err(TOO_MANY_LVARS);

    local_var_stack[lvartos]=i;
    lvartos++;
}

/* Pop index into local variable stack */
int func_pop()
{
    functos--;
    if(functos<0) 
        sntx_err(RET_NOCALL);
    return (call_stack[functos]);
            
}
                 
/* Push index of local variable stack */
void func_push(int i)
{
    if(functos > NUM_FUNC)
        sntx_err(NEST_FUNC);
    call_stack[functos]=i;
    
    functos++;
}
                 

/* Assign a value to a variable */
void assign_var(char *var_name, int value)
{
    register int i;
    
    /* first, see if it's a local variable */
    for(i=lvartos-1;i>= call_stack[functos-1];i--);{
        if(!strcmp(local_var_stack[i].var_name,var_name)){
            local_var_stack[i].value=value;
            return;
        }
    }
    if(i<call_stack[functos-1])
        /* if not local, try global var table */
        for (i=0;i < NUM_GLOBAL_VARS;i++)
            if(!strcmp(global_vars[i].var_name,var_name)){
                global_vars[i].value=value;
                return;
            }
    sntx_err(NOT_VAR);
}


/*  Find the value of a variable */
int find_var(char *s)
{
    register int i;
    
    /* first, see if it's a local variable */
    for(i=lvartos-1;i>= call_stack[functos-1];i--)
        if(!strcmp(local_var_stack[i].var_name,token))
            return local_var_stack[i].value;
            
       
    /* otherwise, try global vars */
    for (i=0;i < NUM_GLOBAL_VARS;i++)
        if(!strcmp(global_vars[i].var_name,s))
            return global_vars[i].value;
    
    sntx_err(NOT_VAR);
    return -1;
}


/*  Determine if an identifier is variable.
    Return 1 if var is found;o otherwise
 */
int is_var(char *s)
{
    register int i;
    
    /* first, see if it's a local variable */
    for(i=lvartos-1;i>= call_stack[functos-1];i--)
        if(!strcmp(local_var_stack[i].var_name,token))
            return 1;
    
    
    /* otherwise, try global vars */
    for (i=0;i < NUM_GLOBAL_VARS;i++)
        if(!strcmp(global_vars[i].var_name,s))
            return 1;
    
    return 0;
}

/*  Execute an IF statement */
void exec_if()
{
    int cound;
    
    eval_exp(&cound);   /* get left expression */
    
    if(cound){
        interp_block();
    }
    else{
        find_eob();
        get_token();
        if(tok!=ELSE){
            putback();
            return;
        }
        interp_block();
    }
}

/*  Execute a while loop */
void exec_while()
{
    int cound;
    char *temp;
    
    putback();
    temp=prog;  /* save location of top of while loop */
    
    get_token();
    eval_exp(&cound);   /* check the conditional expression */
    if(cound)
        interp_block();
    else{               /* skip around loop */
        find_eob();
        return;
    }
    prog=temp;          /* loop back to top */
}


/*  Execute a Do loop */
void exec_do()
{
    int cound;
    char *temp;
    
    putback();
    temp=prog;
    
    get_token();
    interp_block();
    get_token();
    if(tok!=WHILE) 
        sntx_err(WHILE_EXPECED);
    eval_exp(&cound);
    
    if(cound)       
        /* if tru loop; otherwise, continue on */
        prog=temp; 
}

/*  Find the end of a block */
void find_eob()
{
    int brace;
    
    get_token();
    brace=1;
    do {
        get_token();
        if(*token=='{')
            brace++;
        else if (*token=='}')
            brace--;
    } while(brace);
}

/*  Execute a for loop */
void exec_for()
{
    int cound;
    char *temp,*temp2;
    int brace;
    
    get_token();
    eval_exp(&cound);   /* initialization expression */
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
    prog++; /* get past hte ; */
    temp=prog;
    
    for(;;){
        eval_exp(&cound);   /* check the condition */
        if (*token!=';')
            sntx_err(SEMI_EXPECTED);
        prog++;
        temp2=prog;
        
        /* find the start of the block */
        brace=1;
        while(brace){
            get_token();
            if(*token=='(')
                brace++;
            if(*token==')')
                brace--;
        }
        
        if(cound) interp_block();
        else{
            find_eob();
            return;
        }
        prog=temp2;
        eval_exp(&cound);
        prog=temp;
    }
}

Jul 1

这是一个精简的C 解释器的语义剖析器的代码,从《THE CRAFT OF C》上一行一行打下来,可以编译通过,但无法正常运行。若有朋友知道怎样改写,本人将感激不尽!

The entire code for little C recursive-descent parser is shown here,along with some necessary support functions,global data,and data types.

 

//
//  parser.c
//  cinterp
//
//  Created by long on 12. 6. 16..
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//  
//  Recursive descent parser for integer expressions
//  which may include variables and function calls.
//


#include "setjmp.h"
#include "math.h"
#include "ctype.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"

#define NUM_FUNC        100
#define NUM_GLOBAL_VARS 100
#define NUM_LOCAL_VARS  200
#define ID_LEN          31
#define FUNC_CALLS      31
#define PROG_SIZE       10000
#define FOR_NEST        31

enum tok_types {
    DELIMITER, IDENTIFIER, NUMBER, KEYWORD,
    TEMP, STRING, BLOCK
};

enum tokens{
    ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE,
    SWITCH, RETURN, EOL, FINISHED, END
};

enum double_ops{LT=1, LE, GT, GE, EQ, NE};

/*  These are the constants used to call sntx_err() when
    a syntax error occurs. Add more if you like.

    NOTE: SYNTAX is a generic error message used when 
    nothing else seems appropriate.
*/

enum error_msg {
    SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,
    NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
    UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
    NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
    WHILE_EXPECED, QUOTE_EXPECTED, NOT_TEMP,
    TOO_MANY_LVARS
};

extern char *prog;  /* current location in source code */
extern char *p_buf; /* points to start of program buffer */
extern jmp_buf e_buf;   /* hold environment for longjmp() */


/*  An array of these structures will hold the info
    associated with global variables.
 */
extern struct var_type{
    char var_name[32];
    int var_type;
    int value;
}  global_vars[NUM_GLOBAL_VARS];


/* This is the function call stack */
extern struct func_type{
    char func_name[32];
    char *loc;        /* location of function entry point in file */
} func_stack[NUM_FUNC];

/* Keyword table */
extern struct commands{
    char command[20];
    char tok;
}table[];

/*  "Standard Library" functions are declared here so
    they can be put into the internal function table that
    follows.
 */
int call_getche(void),call_putch(void);
int call_puts(void),print(void),getnum(void);

struct intern_func_type{
    char *f_name;   /* functionname */
    int (* p)();    /* pointer to the function */
} intern_func[]={
    "getche",call_getche,
    "putch",call_putch,
    "puts",call_puts,
    "print",print,
    "getnum",getnum,
    "",0    /* null terminate the list */
};

extern char token[80];  /* string representation of token */
extern char token_type; /* contains type of token */
extern char tok;        /* internal representation of token */

extern int ret_value; /* function return value */

void eval_exp(int *value);
void eval_exp1(int *value);
void eval_exp2(int *value);
void eval_exp3(int *value);
void eval_exp4(int *value);
void eval_exp5(int *value);
void eval_exp0(int *value);
void atom(int *value);
void sntx_err(int error),putback(void);
void assign_var(char *var_name, int value);
int isdelim(char c),look_up(char *s), iswhite(char c);
int find_var(char *s),get_token(void);
int internal_func(char *s);
int is_var(char *s);
char *find_func(char *name);
void call(void);

/* Entry point into parser. */
void eval_exp(int *value)
{
    get_token();
    if(!*token){
        sntx_err(NO_EXP);
        return;
    }
    if(*token==';'){
        *value=0;   /* empty expression */
        return;
    }
    eval_exp0(value);
    putback();  /* return last token read to input stream */
}


/* Process an assignment expression */
void eval_exp0(int *value)
{
    /* holds name of var receiving the assignment */
    char temp[ID_LEN];

    register int temp_tok;
    
    if(token_type==IDENTIFIER){
        if(is_var(token)){  /* if a var, see if assignment */
            strcpy(temp,token);
            temp_tok=token_type;
            get_token();
            if(*token=='='){    /* is an assignment */
                get_token();
                eval_exp0(value);   /* get value to assign */
                assign_var(temp,*value);    /* assign the value */
                return;
            }
            else{   /* not an assignment */
                putback();  /*restore original token */
                strcpy(token,temp);
                token_type=temp_tok;
            }
        }
    }
    eval_exp1(value);
}


/*  This array is used by eval_exp1(). Because
    some compilers cannot initialize an array within a
    function it is defined as a global variable.
 */
char relops[7]={
    LT, LE, GT, GE, EQ, NE, 0
};

/* Process relational operators. */
void eval_exp1(int *value)
{
    int partial_value;
    register char op;
    
    eval_exp2(value);
    op=*token;
    if(strchr(relops,op)){
        get_token();
        eval_exp2(&partial_value);
        switch(op){     /* perform the relational operation */
            case LT:
                *value=*value < partial_value;
                break;
            case LE:
                *value=*value <= partial_value;
                break;
            case GT:
                *value=*value > partial_value;
                break;
            case GE:
                *value=*value >= partial_value;
                break;
            case EQ:
                *value=*value == partial_value;
                break;
            case NE:
                *value=*value != partial_value;
                break;
        }
    }
}


/* Add or substract two terms. */
void eval_exp2(int *value)
{
    register char op;
    int partial_value;
    
    eval_exp3(value);
    while((op=*token)=='+' || op=='-'){
        get_token();
        eval_exp3(&partial_value);
        switch(op){
            case '-':
                *value=*value-partial_value;
                break;
            case '+':
                *value =*value +partial_value;
                break;
        }
        
    }
}

/* Multiply or divide two factore. */
void eval_exp3(int *value)
{
    register char op;
    int partial_value,t;
    
    eval_exp4(value);
    while((op=*token) == '*' || op=='/' || op=='%'){
        get_token();
        eval_exp4(&partial_value);
        switch(op){
            case '*':
                *value= *value * partial_value;
                break;
            case '/':
                *value= (*value)/ partial_value;
                break;
            case '%':
                t=(*value)/partial_value;
                *value= *value-(t*partial_value);
                break;
        }
    }
}


/* Is a unary + or -. */
void eval_exp4(int *value)
{
    register char op;
    
    op='\0';
    if(*token=='+' || *token=='-'){
        op=*token;
        get_token();
    }
    eval_exp5(value);
    if(op && op=='-') 
        *value = -(*value);
}


/* Process parenthesized expression. */
void eval_exp5(int *value)
{
    if((*token=='(')){
        get_token();
        eval_exp0(value);   /* get subexpression */
        if(*token != ')')
            sntx_err(PAREN_EXPECTED);
        get_token();
    }
    else{
        atom(value);
    }
}

/* Find value of number, variable or function. */
void atom(int *value)
{
    int i;
    
    switch(token_type){
        case IDENTIFIER:
            i=internal_func(token);
            if(i != -1){    /* call "standard library" function */
                *value = (*intern_func[i].p)();
            }
            else if (find_func(token)){ /* call user-defined function */
                call();
                *value =ret_value;
            }
            else *value =find_var(token);   /* get bar's value */
            get_token();
            return;
        case NUMBER:
            *value = atoi(token);
            get_token();
            return;
        case DELIMITER: /* see if character constant */
            if(*token=='\''){
                *value= *prog;
                prog++;
                if(*prog!='\'') sntx_err(QUOTE_EXPECTED);
                prog++;
                get_token();
            }
            return;
        default:
            if( *token== ')') return;   /* process empty expression */
            else sntx_err(SYNTAX);
    }
}


/* Display an error message. */
void sntx_err(int error)
{
    char *p,*temp;
    int linecount=0;
    register int i;
    
    static char *e[]={
        "syntax error",
        "unbalanced parentheses",
        "no expression present",
        "equals sign expected",
        "not a variable",
        "parameter error",
        "semicolon expected",
        "unbalanced braces",
        "function undefined",
        "type specifier expected",
        "too many nested function calls",
        "return without call",
        "parentheses expected",
        "while expected",
        "closing quote expected",
        "not a string",
        "too many local variables"
    };
    
    printf("%s",e[error]);
    p=p_buf;
    while(p!=prog){
        p++;
        if(*p =='\r'){
            linecount++;
        }
    }
    printf(" line %d\n",linecount);
    
    temp=p;
    for(i=0;i<20 && p>p_buf && *p!='\n';i++,p--);
    for(i=0;i<30 && p<=temp;i++,p++)
        printf("%c",*p);
    
    longjmp(e_buf,1);   /* return to save point */
}

/* Get a token */
int get_token()
{
    register char *temp;
    
    token_type=0;
    tok=0;
    
    temp=token;
    *temp='\0';
    
    /* skip over white space */
    while(iswhite(*prog) && *prog) ++prog;
    
    if(*prog=='\r'){
        ++prog;
        ++prog;
        /* skip over white space */
        while(iswhite(*prog) && *prog) ++prog;
    }
    
    if( *prog=='\0'){   /* end of file */
        *token='\0';
        tok=FINISHED;
        return(token_type=DELIMITER);
    }
    
    if(strchr("{}",*prog)){ /* block delimiters */
        *temp= *prog;
        temp++;
        *temp='\0';
        prog++;
        return (token_type=BLOCK);
    }
    
    /* look for comments */
    if(*prog=='/')
        if(*(prog+1)=='*'){
            prog+=2;
            do{
                while (*prog != '*') prog++;
                prog++;
            } while (*prog !='/');
            prog++;
        }
    
    /* is or might be a relation operator */
    
    if(strchr("!<>=",*prog)){
        switch(*prog){
            case '=':
                if(*(prog+1) =='='){
                    prog++;
                    prog++;
                    *temp=EQ;
                    temp++;
                    *temp=EQ;
                    temp++;
                    *temp='\0';
                }
                break;
            case '!':
                if(*(prog+1)=='='){
                    prog++; prog++;
                    *temp=NE;
                    temp++;
                    *temp=NE;temp++;
                    *temp='\0';
                }
                break;
            case '<':
                if(*(prog+1)=='='){
                    prog++; prog++;
                    *temp=LE;
                    temp++;
                    *temp=LE;
                }
                else{
                    prog++;
                    *temp=LT;
                }
                temp++;
                *temp='\0';
                break;
            case '>':
                if(*(prog+1)=='='){
                    prog++; prog++;
                    *temp=GE;
                    temp++;
                    *temp=GE;
                }
                else{
                    prog++;
                    *temp=GT;
                }
                temp++;
                *temp='\0';
                break;
        }
        if( *token) return (token_type=DELIMITER);
    }
    
    if(strchr("+-*/^%=;(),'",*prog)){
        *temp=*prog;
        prog++;     /* advance to next position */
        temp++;
        *temp='\0';
        return (token_type=DELIMITER);
    }
    
    if( *prog=='"'){    /* quoted string */
        prog++;
        while(*prog!='"' && *prog!='\r')
            *temp++ = *prog++;
        if(*prog=='\r') sntx_err(SYNTAX);
        prog++;
        *temp='\0';
        return (token_type=STRING);
    }
    
    if(isdigit(*prog)){
        while(!isdelim(*prog))
            *temp++ = *prog++;
        *temp='\0';
        return (token_type=NUMBER);
    }
    
    if(isalpha(*prog)){ /* var or command */
        while(!isdelim(*prog))
            *temp++ = *prog++;
        token_type=TEMP;
    }
    
    *temp ='\0';
    
    /* see if a string is a command or a variable */
    if(token_type==TEMP){
        tok=look_up(token); /* convert to internal rep */
        if(tok)
            token_type=KEYWORD;
        else token_type=IDENTIFIER;
    }
    return token_type;
}


/* Return a token to input stream */
void putback()
{
    char *t;
    
    t=token;
    for(;*t;t++)
        prog--;
}

/*  Look up a token's internal representation in the
    token table.
 */
int look_up(char *s)
{
    register int i;
    char *p;
    
    /* convert to lowercase */
    p=s;
    while(*p){
        *p=tolower(*p);
        p++;
    }
    
    /* see if token is in table */
    for(i=0; *table[i].command; i++)
        if(!strcmp(table[i].command,s))
            return table[i].tok;
    return 0;   /* unknown command */
}

/*  Return index of internal library function or -1 
    if not found.
 */
int internal_func(char *s)
{
    int i;
    
    for(i=0;intern_func[i].f_name[0];i++){
        if(!strcmp(intern_func[i].f_name,s))
            return i;
    }
    return -1;
}

/* Return true if c is a delimiter. */
int isdelim(char c)
{
    if(strchr(" !;,+-<>'/*%^=()",c) || c==9||
       c=='\r' || c==0)
        return 1;
    return 0;
}

/* Return 1 if c is space or tab. */
int iswhite(char c)
{
    if(c==' ' || c=='\t') return 1;
    else return 0;
}


 

原书上推荐用Turbo/Borland C/C++ 或Microsoft C/C++

命令:tcc -c parser.c

           c1 -c parser.c

Jun 19

对于scanf()函数来说," ","\t","\n"并没有什么本质的区别,scanf()函数遇到这三种字符的时候会停止,但是这些字符会变成当前缓冲区中的字符。也就是 说,scanf("%d",&n);语句作用完之后,如果还有回车,那么scanf("%c",&ch);读入的就是一个回车。

但是scanf("\n")所读取的并不是一个回车,而是之后所有的" ","\t","\n"字符!其实这就是把缓冲区中所有的" ","\t","\n"字符都清空了。scanf(" ");和scanf("\t");在这方面的功能与scanf("\n");并没有什么区别。

相比之下,gets()要稍微规范一点,可惜的是gets()容易出现溢出错误,所以不建议使用。gets()仅仅是读入到"\n"字符为止,但是 与scanf()不同的是,gets()不会把这个遇到的"\n"字符放入缓冲区,而且gets()所跳过的仅仅是这一个"\n"字符!也就是 说,gets()函数永远是读入到当前行为止,并且自动转到下一行的开头。