1.9规则动作详细设计

1.9.1 概述

该部分,除了包括{loc}中提到的单词的识别,还将介绍如何匹配、缓存并返还下一行;如何处理字符常量识别的各种情况;如何处理遇到文件尾的各种情况;如何处理单行注释;如何处理多行注释等;如何处理非法字符等情况。

PASCAL-S的单行注释以//开始,多行注释由一对花括号包括。

1.9.2 环境介绍

名称 描述 进入条件 离开条件
INITIAL 初始环境(默认环境) lex开始运行,或从CH、SCOM、MCOM返回 遇到单引号、双斜杠、左花括号
CH 字符常量识别环境 在INITIAL中遇到单引号 遇到单引号、换行符
SCOM 单行注释识别环境 在INITIAL中遇到双斜杠 遇到换行符
MCOM 多行注释识别环境 在INITIAL中遇到左花括号 遇到右花括号

1.9.3 INITIAL环境

1.9.3.1 空白符

  • 正则表达式

    1. {blank_chars}
  • 动作伪代码

  • 说明

     遇到空白符,无需采取任何动作。
    

    1.9.3.2 缓存下一行

  • 正则表达式

     {line}
    
  • 动作伪代码

    {
      if(检测当前行长度超过限制)//CheckAndAddLengthTooLargeErrorInformation
      return 0;
      将当前行保存到lineBuffer中;
      yycolumn初始化为1;
      将当前行全部退回到输入区,只保留一开始的换行符;
    }
    
  • 说明

     下一行的起始标志是换行符,因此为了识别第一行,在预处理中,我们在整个源程序的第一行之前加入了一个换行符;另外加入换行符也会影响到yylineno及行号,真正的行号应为yylineno-1。<br />       缓存下一行的主要目的是为了输出更加详细的词法错误信息。可以先指明错误类型,然后输出错误所在行,最后用”^”符号指出错误的具体位置。
    

    1.9.3.3 各种单词通用设计

  • 正则表达式

program const var array
of procedure function begin
if then for to
do else repeat until
while {_type} not {relop}
{addop} {mulop} - =
:= \.\. {delimiter}
  • 动作伪代码

    {
      yylval指向新创建的节点;
      根据当前的单词种类,对yylval的记号和属性域进行赋值;
      yylval的行号域赋值为当前行号;
      return 当前记号;
    }
    
  • 说明

     各单词的记号和属性信息在{loc}中已详细说明,不再赘述。
    

    1.9.3.4 单引号,进入CH环境

  • 正则表达式

  • 动作伪代码

    {
      进入CH环境;
      charRec初始化为空字符串;
    }
    

    1.9.3.5 双斜杠,进入SCOM环境

  • 正则表达式

     \/\/
    
  • 动作伪代码

    {  
      进入SCOM环境;  
    }
    

    1.9.3.6 左花括号,进入MCOM环境

  • 正则表达式

     \{
    
  • 动作伪代码

    {  
      进入MCOM环境;  
    }
    

1.9.3.7 非法字符

  • 正则表达式

     .
    
  • 动作伪代码

    {  
      添加非法字符错误;//错误3  
    }
    

1.9.4 CH环境

1.9.4.1 文件尾

  • 正则表达式

     <CH><<EOF>>
    
  • 动作伪代码

    {  
      添加读取字符常量时遇到文件尾的错误;//错误4  
    }
    

1.9.4.2 单引号或换行符,进入INITIAL环境

  • 正则表达式

     <CH>("'"|"\n")
    
  • 动作伪代码

    {
      len=charRec记录的字符串的长度;
      if(当前识别的是单引号 && len==0) {
          添加字符常量为空的错误信息;
          //错误5
          返回到初始环境;
          yylval指向新创建的节点;
          yylval的属性为"\0";
          yylval的记号为CHAR;
          yylval的行号域赋值为当前行号;
          return CHAR;
      } else if(当前识别的是单引号 && len==1) {
          yylval指向新创建的节点;
          返回到初始环境;
          yylval的属性为charRec[0];
          yylval的记号为CHAR;
          yylval的行号域赋值为当前行号;
          return CHAR;
      } else if(当前识别的是单引号 && len>1) {
          添加字符常量过长的错误信息;
          //错误6
          yylval指向新创建的节点;
          返回到初始环境;
          yylval的属性为charRec[0];
          yylval的记号为CHAR;
          yylval的行号域赋值为当前行号;
          return CHAR;
      } else {
          //当前识别的是换行符
          添加右单引号缺失的错误信息;
          //错误7
          yylval指向新创建的节点;
          返回到初始环境;
          if(len==0)
          yylval的属性为"\0"; else
          yylval的属性为charRec[0];
          yylval的记号为CHAR;
          yylval的行号域赋值为当前行号;
          return CHAR;
      }
    }
    

1.9.4.3 其它字符

  • 正则表达式

     <CH>.
    
  • 动作伪代码

    {  
      charRec后面拼上yytext[0];  
    }
    

1.9.5 SCOM环境

1.9.5.1 文件尾

  • 正则表达式

     <SCOM><<EOF>>
    
  • 动作伪代码

    {  
      return 0;//表示分析结束  
    }
    
  • 说明

     单行注释遇到文件尾是很正常的情况。
    

    1.9.5.2 换行符,进入INITIAL环境

  • 正则表达式

     <SCOM>"\n"
    
  • 动作伪代码

    {
      返回到初始环境;
      将换行符退回;
      当前行号减1;
    }
    

1.9.5.3 其它字符

  • 正则表达式

     <SCOM>.
    
  • 动作伪代码

    1.9.6 MCOM环境

    1.9.6.1 文件尾

  • 正则表达式

     <MCOM><<EOF>>
    
  • 动作伪代码

    {
      添加多行注释遇到文件尾的错误信息;
      return 0;
      //词法分析终止
    }
    

1.9.6.2 缓存下一行

  • 正则表达式

     <MCOM>{line}
    
  • 动作伪代码

    {
      if(检测当前行长度超过限制)//CheckAndAddLengthTooLargeErrorInformation
      return 0;
      将当前行保存到lineBuffer中;
      yycolumn初始化为1;
      将当前行全部退回到输入区,只保留一开始的换行符;
    }
    

1.9.6.3 右花括号,进入INITIAL环境

  • 正则表达式

     <MCOM>"\}"
    
  • 动作伪代码

    {
      返回到初始环境;
    }
    

1.9.6.4 其它字符

  • 正则表达式

     <MCOM>.
    
  • 动作伪代码