1.1函数返回值语句存在性检测(警告信息)

函数如果没有返回值语句,则其返回值将会是一个随机的值,许多编译器都将其作为一个警告检测,我们也简单的实现了一个函数返回值语句的存在性检测,如果检测到有函数没有或缺少返回值语句,则输出警告信息。

1.1.1 算法分析

按照文法定义,函数定义中的语句体一定是一个复合语句块_Compound。_Compound中的任何一条语句是返回值语句或“完全”地包含返回值语句,就可以认为该函数定义存在足够的返回值语句。_Compound的语句列表中的每一条语句,具体类型可能各不相同,不同的语句对于返回值语句的考虑也不太一样。
我们首先定义一个概念,“返回值完备”,下面是对其的递归定义:

  • 如果一条语句是赋值形式的返回值语句或者exit过程调用形式的返回值语句,就认为该语句是“返回值完备”的
  • 如果_Compound语句中,有任意一条语句是“返回值完备”的,那么该_Compound语句就是“返回值完备”的
  • 如果_RepeatStatement、_WhileStatement、_ForStatement的循环体语句是“返回值完备”的,那么该语句就是“返回值完备”的
  • 如果_IfStatement包含then语句和else语句,且这两条语句均是“返回值完备”的,那么该_IfStatement语句就是“返回值完备”的
  • 如果函数定义的_Compound程序体是“返回值完备”的,那么该函数定义是“返回值完备”的

下面以表格的形式进行阐述:

语句种类 分析
_Compound 语句列表中,只要存在有任何一条语句是返回值语句或“完全”地包含返回值语句,就可以认为该_Comound语句是“返回值完备”的。
_RepeatStatement 如果循环体语句是“返回值完备”的,就可以认为该_RepeatStatement语句是“返回值完备”的。
_WhileStatement 如果循环体语句是“返回值完备”的,就可以认为该_RepeatStatement语句是“返回值完备”的。
_ForStatement 如果循环体语句是“返回值完备”的,就可以认为该_RepeatStatement语句是“返回值完备”的。
_IfStatement 如果_IfStatement不包含else部分,那么无论then语句是否是“返回值完备”,该_IfStatement语句都不是“返回值完备”的;如果_IfStatement包含else部分,那么当then语句和else语句都是“返回值完备”时,就可以认为该_IfStatement语句是“返回值完备”的,否则就认为该­_IfStatement语句不是“返回值完备”的。
_AssignStatement 如果是赋值语句形式的函数返回值语句,就认为该_AssignStatement语句是“返回值完备”的
_ProcedureCall 如果是exit过程调用形式的函数返回值语句,就认为该_ProcedureCall语句是“返回值完备”的

1.1.2 数据结构

涉及的数据结构只有保存警告信息的列表,声明如下:

  1. extern vector<string> semanticWarningInformation;
  1. 其定义在SemanticAnalyse.cpp中,因此这里需要用extern关键字声明。

1.1.3 警告信息格式设计

  • 需要提供函数名functionId和函数名所在的行号functionLineNumber
  • 格式为:[Return value statement missing!] Incomplete return value statement of function “{functionId}”.

    1.1.4 引用外部的函数接口

    1.1.4.1 整型数字转化为字符串

  • 函数接口

    extern string itos(int num);//将整数转化为字符串
    

1.1.5 内部函数接口

1.1.5.1 检查当前语句是否是“返回值完备”的

  • 函数接口

    bool returnExistedCheckStatement(_Statement *statementNode);
    
  • 参数列表 | 参数 | 描述 | | —- | —- | | _Statement *statementNode | 语句基类指针 |

  • 返回值

     bool,true表示当前语句是“返回值完备”的,false表示当前语句不是“返回值完备的”
    
  • 伪代码

    bool returnExistedCheckStatement(_Statement *statementNode) {
      if (statementNode == NULL) {
          cout << "[returnExistedCheckStatement] pointer of _Statement is null" << endl;
          return false;
      }
      if (是compound语句) {
          _Compound *compound = reinterpret_cast<_Compound*>(statementNode);
          遍历语句列表 {
              调用returnExistedCheckStatement检查当前语句的“返回值完备”性;
              if(当前语句是返回值完备的)
                  return true;
          }
          return false;
      }
      else if (是repeat语句) {
          _RepeatStatement *repeatStatement = reinterpret_cast<_RepeatStatement*>(statementNode);
          调用returnExistedCheckStatement检查循环体语句的“返回值完备”性;
         if(循环体语句是“返回值完备”的)
              return true;
         else
              return false;
      }
      else if (是while语句) {
          _WhileStatement *whileStatement = reinterpret_cast<_WhileStatement*>(statementNode);
          调用returnExistedCheckStatement检查循环体语句的“返回值完备”性;
         if(循环体语句是“返回值完备”的)
              return true;
         else
              return false;
      }
      else if (是for语句) {
          _ForStatement *forStatement = reinterpret_cast<_ForStatement*>(statementNode);
          调用returnExistedCheckStatement检查循环体语句的“返回值完备”性;
         if(循环体语句是“返回值完备”的)
              return true;
         else
              return false;
      }
      else if (是if语句) {
          _IfStatement *ifStatement = reinterpret_cast<_IfStatement*>(statementNode);
          if (ifStatement->then == NULL) {
              cout << "[returnExistedCheckStatement][IfStatement] the pointer of then statement is null";
              return false;
          }
          if (if语句不包含else部分) 
              return false;
          else{
              调用returnExistedCheckStatement检测then语句和else语句的“返回值完备”性;
              if(then语句和else语句都是“返回值完备”的)
                  return true;
              else
                  return false;
         }
      }
      else if (是赋值语句) { //判断是否是返回值语句
          _AssignStatement *assignStatement = reinterpret_cast<_AssignStatement*>(statementNode);
          return assignStatement->isReturnStatement; //在之前的语义分析中,已经保存是否是返回值语句
          //即fun:=expression的情况
      }
      else if (是过程调用) { //判断是否是返回值语句
          _ProcedureCall *procedureCall = reinterpret_cast<_ProcedureCall*>(statementNode);
          return procedureCall->isReturnStatement; //在之前的语义分析中,已经保存是否是返回值语句
          //即exit()的情况
      }
      else {
          cout << "[returnExistedCheckStatement] statement type error" << endl;
          return false;
      }
    }
    

1.1.5.2 检查函数定义的程序体语句列表是否是“返回值完备”的

  • 函数接口

    void returnExistedCheckMainCompound(_Compound *compoundNode, string functionId, intfunctionLineNumber);
    
  • 参数列表 | 参数 | 描述 | | —- | —- | | _Compound *compoundNode | 程序体语句列表 | | string functionId | 函数名 | | int functionLineNumber | 函数名所在的行号 |

  • 返回值

  • 伪代码

    void returnExistedCheckMainCompound(_Compound *compoundNode, string functionId, intfunctionLineNumber) {
      if (compoundNode == NULL) {
          cout << "[returnExistedCheckCompound] pointer of _Compound is null" << endl;
          return;
      }
      bool ok = false; //表示当前复合语句块的“返回值完备”性,true表示具有“返回值完备”性,false表示不具有“返回值完备”性
      遍历复合语句块的语句列表 {
         调用returnExistedCheckStatement检测当前语句的“返回值完备”性;
         if(当前语句是返回值完备的){
              ok=true;
              break;
         }
      }
      if (复合语句块不是“返回值完备”的) {
         按照函数缺少返回值语句的警告信息格式组织functionId、functionLineNumber,形成一条警告信息;
         将警告信息添加到警告信息列表中;
      }
    }
    

1.1.5.3 检查函数定义是否是“返回值完备”的

  • 函数接口

    void returnExistedCheckFunctionDefinition(_FunctionDefinition* functionDefinitionNode);
    
  • 参数列表 | 参数 | 描述 | | —- | —- | | _FunctionDefinition* functionDefinitionNode | 函数定义节点类指针 |

  • 返回值

  • 伪代码