词法分析器只做token识别,代码详细注释

mian.c

#include "globals.h"

/**创建只扫描的编译器 **/
#define NO_PARSE TRUE

#include "scan.h"///词法分析,核心过程为扫描函数 //如果NO_PARSE为true,调用头文件scan.h

/** 分配全局变量 */
int lineno = 0;
FILE * source; ///源代码文件
FILE * listing; ///显示分析过程的文件,这里重定向到stdout
FILE * code; ///目标汇编代码文件

/** 分配并初始化追踪标志 / 直接运行main.c看不到结果  需将下列部分变量的值从FALSE改为TRUE,表示分部执行相应操作 */
int EchoSource = TRUE;  ///将TINY源程序回显到带有行号的列表-->改为true才能执行
int TraceScan = TRUE;  ///当扫描程序识别出记号时,就显示每个记号的信息

main( int argc, char * argv[] )
{
  char pgm[120]; /** 源代码文件名称 */
  if (argc != 2)
    { fprintf(stderr,"usage: %s <filename>\n",argv[0]);
      exit(1); ///如果argv不为2,打印显示信息并退出【意为如果输入不是:tiny 文件名.文件类型 假如多输入了个1就表示有三个参数,则错误】
    }
  strcpy(pgm,argv[1]) ; ///复制argv[1]地址以null为退出字符的存储器区块到另一个存储器区块品pgm内
  if (strchr (pgm, '.') == NULL)
     strcat(pgm,".tny"); ///把.tny文件所指字符串添加到pgm结尾处并添加'\0'
  source = fopen(pgm,"r"); ///以只读的方式打开pgm文件,并将指向pgm文件的指针返回给source
  if (source==NULL)
  { fprintf(stderr,"File %s not found\n",pgm);
    exit(1); ///  如果源文件没有被找到,输出文件没有被找到
  }
  listing = stdout; /** 发清单消息到屏幕 */
  fprintf(listing,"\nTINY COMPILATION: %s\n",pgm); ///应答显示语句


while (getToken()!=ENDFILE); ///如果输入流没有结束就继续进行循环,直至结束

  fclose(source); ///关闭源代码文件
  return 0;
}
globals.h
///全局定义.包括了数据类型的定义和整个编译器均使用的全程变量,任何代码文件都包含了globals.h头文件

#ifndef _GLOBALS_H_
#define _GLOBALS_H_  ///宏定义

#include <stdio.h>
#include <string.h> ///头文件引用

#ifndef FALSE
#define FALSE 0 //定义FALSE为0
#endif

#ifndef TRUE
#define TRUE 1 //定义TRUE为1
#endif

///定义了关键字个数8个
#define MAXRESERVED 8

typedef enum
    /* book-keeping tokens */
   {ENDFILE,ERROR,
    /* 保留字 */
    IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,
    /* 标识符 */
    ID,NUM,
    /* 特殊符号 */
    ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI
   } TokenType;  /// 定义了关键字,运算符等内容的枚举值

extern FILE* source; /* 源代码文本文件 */ ///extern用在变量或函数前,表示变量或函数的定义在其他文件中
extern FILE* listing; /// 显示分析过程的文件的地址 */


extern int lineno; /* 源代码行数清单 */

/* EchoSource = TRUE causes the source program to
 * be echoed to the listing file with line numbers
 * during parsing
 */
extern int EchoSource;

/* TraceScan = TRUE causes token information to be
 * printed to the listing file as each token is
 * recognized by the scanner
 */
extern int TraceScan;

#endif

scan.h
///对于tiny编译器的扫描程序接口

#ifndef _SCAN_H_
#define _SCAN_H_

/** maxtokenlen是token的最大大小*/
#define MAXTOKENLEN 40

/** tokenString数组保存每个token */
extern char tokenString[MAXTOKENLEN+1];

/** 函数getToken返回源程序中的下一个token*/
TokenType getToken(void);


#endif

scan.c

#include "globals.h"
#include "scan.h"


/**定义的状态 */
typedef enum
   { START,///初始状态
   INASSIGN,///进入到赋值状态
   INCOMMENT,///进入到注释状态
   INNUM,///进入到数字状态
   INID,///进入到标志符状态
   DONE  ///状态结束
   }StateType; /**每当语法分析程序需要一个单词时,就调用该子程序,得到 (类别码,单词的值)*/




/** 语义标识符和保留字*/
char tokenString[MAXTOKENLEN+1];




/** BUFLEN = 源代码的输入缓冲长度 */
#define BUFLEN 256


static char lineBuf[BUFLEN]; /** 当前行 */
static int linepos = 0; /** 在linebuf中的当前位置*/
static int bufsize = 0;  /** 缓冲区的字符串当前大小*/
static int EOF_flag = FALSE; /** 如果读入下一个字符出错,设置EOF_flag为假。*/


/** getNextChar获取下一个非空白字符开始从lineBuf,如果读完,则读入新行*/
static int getNextChar(void)
{ if (!(linepos < bufsize))
  { lineno++;
    if (fgets(lineBuf,BUFLEN-1,source))
    { if (EchoSource) fprintf(listing,"%4d: %s",lineno,lineBuf);
      bufsize = strlen(lineBuf);
      linepos = 0;
      return lineBuf[linepos++];
    }
    else
    { EOF_flag = TRUE;
      return EOF;
    }
  }
  else return lineBuf[linepos++];
}



/** 如果读入下一个字符出错,在linebuf中回退一个字符 。*/
static void ungetNextChar(void)
{ if (!EOF_flag) linepos-- ;}


/** 保留字的查找表 */
static struct
    { char* str;
      TokenType tok;
    } reservedWords[MAXRESERVED]
   = {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
      {"repeat",REPEAT},{"until",UNTIL},{"read",READ},
      {"write",WRITE}};




 /** 标识符是否是保留字*/
static TokenType reservedLookup (char * s)
{ int i;
  for (i=0;i<MAXRESERVED;i++)
    if (!strcmp(s,reservedWords[i].str))
      return reservedWords[i].tok;
  return ID;
}


/****************************************/
/**********扫描仪的主要功能*************/
/****************************************/




/** 函数gettoken返回源文件中下一个标记 */
TokenType getToken(void)
{  /** 存入tokenstring的位置 */
   int tokenStringIndex = 0;
   /** 保存当前要返回的token; */
   TokenType currentToken;
   /** 当前状态 */
   StateType state = START;
   /** 表示保存到tokenstring的flag */
   int save;
   while (state != DONE)
   { int c = getNextChar(); /**从输入buf中读入一个字符*/
     save = TRUE;
     switch (state)
     { case START:
         if (isdigit(c)) /**判断字母*/
           state = INNUM;
         else if (isalpha(c))
           state = INID;
         else if (c == ':')
           state = INASSIGN;
         else if ((c == ' ') || (c == '\t') || (c == '\n'))
           save = FALSE;
         else if (c == '{')
         { save = FALSE;
           state = INCOMMENT;
         }
         else
         { state = DONE;
           switch (c)
           { case EOF:
               save = FALSE;
               currentToken = ENDFILE;
               break;
             case '=':
               currentToken = EQ;
               break;
             case '<':
               currentToken = LT;
               break;
             case '+':
               currentToken = PLUS;
               break;
             case '-':
               currentToken = MINUS;
               break;
             case '*':
               currentToken = TIMES;
               break;
             case '/':
               currentToken = OVER;
               break;
             case '(':
               currentToken = LPAREN;
               break;
             case ')':
               currentToken = RPAREN;
               break;
             case ';':
               currentToken = SEMI;
               break;
             default:
               currentToken = ERROR;
               break;
           }
         }
         break;
       case INCOMMENT:
         save = FALSE;
         if (c == EOF)
         { state = DONE;
           currentToken = ENDFILE;
         }
         else if (c == '}') state = START;
         break;
       case INASSIGN:
         state = DONE;
         if (c == '=')
           currentToken = ASSIGN;
         else
         {  /** 在输入中备份 */
           ungetNextChar();
           save = FALSE;
           currentToken = ERROR;
         }
         break;
       case INNUM:
         if (!isdigit(c))
         {  /** 在输入中备份*/
           ungetNextChar();
           save = FALSE;
           state = DONE;
           currentToken = NUM;
         }
         break;
       case INID:
         if (!isalpha(c))
         {  /** 在输入中备份*/
           ungetNextChar();
           save = FALSE;
           state = DONE;
           currentToken = ID;
         }
         break;
       case DONE:
       default: /** 应该不会执行 */
         fprintf(listing,"Scanner Bug: state= %d\n",state);
         state = DONE;
         currentToken = ERROR;
         break;
     }
     if ((save) && (tokenStringIndex <= MAXTOKENLEN))
       tokenString[tokenStringIndex++] = (char) c;
     if (state == DONE)
     { tokenString[tokenStringIndex] = '\0';
       if (currentToken == ID)
         currentToken = reservedLookup(tokenString);
     }
   }
   if (TraceScan) {
     fprintf(listing,"\t%d: ",lineno);
     printToken(currentToken,tokenString);
   }
   return currentToken;
} /* end getToken */


///此函数输出一个标号和一个词素
void printToken( TokenType token, const char* tokenString )
{ switch (token)
  { case IF:
    case THEN:
    case ELSE:
    case END:
    case REPEAT:
    case UNTIL:
    case READ:
    case WRITE:
      fprintf(listing,
         "reserved word: %s\n",tokenString);
      break;
    case ASSIGN: fprintf(listing,":=\n"); break;
    case LT: fprintf(listing,"<\n"); break;
    case EQ: fprintf(listing,"=\n"); break;
    case LPAREN: fprintf(listing,"(\n"); break;
    case RPAREN: fprintf(listing,")\n"); break;
    case SEMI: fprintf(listing,";\n"); break;
    case PLUS: fprintf(listing,"+\n"); break;
    case MINUS: fprintf(listing,"-\n"); break;
    case TIMES: fprintf(listing,"*\n"); break;
    case OVER: fprintf(listing,"/\n"); break;
    case ENDFILE: fprintf(listing,"EOF\n"); break;
    case NUM:
      fprintf(listing,
          "NUM, val= %s\n",tokenString);
      break;
    case ID:
      fprintf(listing,
          "ID, name= %s\n",tokenString);
      break;
    case ERROR:
      fprintf(listing,
          "ERROR: %s\n",tokenString);
      break;
    default: /* should never happen */
      fprintf(listing,"Unknown token: %d\n",token);
  }
}


---->>>>>>用C语言的编译工具创建一个tiny项目,在创建这几个文件,在生成的tiny软件目录,写一个需要识别的txt文本文件,用控制台来到当前目录,输入tiny + 文件名.txt即可看到识别出的效果

效果图:


  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值