zoukankan      html  css  js  c++  java
  • 编译原理之词法分析:三个代表实现消除白空格

    此文是对编译原理学习的部分总结,与一般介绍有限状态机侧重原理不同,本文侧重的是程序实现的思想。程序实现消除字符串中的多余空格,只保留一个,(\r  \n  \t  \s)。

    程序根据键盘先后键入的值,判断是否该输出后键入的值,因此程序的输出有多种情况,输出选择分支时,很多人都只知道用case语句,其实可以使用函数指针数组取代之,这样程序更加简洁、清晰、强大,下面说说具体实现。

    三个代表:

    (1)       字符分类表:描述当前输入的字符的类型,当输入是空格时(对应ASCII码的009、010、013、032),记录为“0”,当输入为普通字符时,记录为“1”。所以整个表只有两种状态,见程序input_tab[],它由输入的字符决定;它对应着有穷自动机中的<no_ws>和<ws>。

    字符分类表:input_tab[]

    字符分类

    非空格

    空格

    状态描述

    <no-ws>

    <ws>

    chin_type

    0

    1

    (2)       状态转换表:根据程序的要求,这里输入的字符状态chin_type只有两种,就是空格(0)和非空格(1),另外,前一次输出动作state_bf也有两种情况,所以,状态的转换对应程序中的state_tran_tab[][],它由当前状态和输入类型决定;它对应有穷自动机大圆中的“0”和“1”。它的值有两个,状态转换过程有四个。

    状态转换表:state_tran_tab[][]

    state_bf   \   chin_type

    0 (非空格)

    1 (空格)

    0

    0

    1

    1

    0

    1

    (3)       输出动作表:用来确定当前读入的字符是否该输出,对应程序中的action_tab[][],由前一次输出的状态(state_bf)和当前状态(state_af)决定当前输出状态,所以状态有四种:字符接字符00,字符接空格01,空格接字符10,空格接空格11,只有最后一种情况不输出,这是一个函数指针数组,由前一次输入类型和当前输入类型决定;它对应着有穷自动机的output和do_nothing两个动作,但是转换过程有四种。

    输出动作表:action_tab[][]

    state_bf   \  state_af

    0 (输出)

    1 (不输出)

    0

    0

    0

    1

    0

    1

    有穷自动机描述如下

     

    其实此图对应着程序的流程图(有穷自动机就是流程图的抽象)。为了更好的解释程序,我在各个状态转换线路上标上了A/B/C/D,下面一一做出解释(A:state_bf==0,当前输入为<no_ws>,回到当前状态,输出动作为out_put; B:state_bf==0,当前输入为<ws>,转换到状态1,输出动作为out_put,因为是第一次遇到空格; D:state_bf==1,当前输入为<ws>,回到当前状态,输出动作为do_nothing,因为连续遇到空格; C:state_bf==1,当前输入为<no_ws>,转换到状态0,输出动作为out_put,因为只遇到一次空格)

    程序代码如下

    #include "stdio.h"

    int input_tab[128]={

                         0,0,0,0,0,0,0,0,0,1,

                         0,0,0,1,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,1,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0,0,0,

                         0,0,0,0,0,0,0,0};

    int state_tran_tab[2][2]={{0,1},{0,1}};

    void (* action_tab[2][2])(char ch)={print,print,print,do_nothing};

    void print(char ch)

    {

    printf("%c",ch);

    }

    void do_nothing(char ch)

    {}

    void translate(char *input)

    {

        int i=0;

        int state_af=0,state_bf=0;

        int chin_type=0;

        while(input[i]!='\0')

        {

          int  chin=input[i];

          if(0<=chin<=128)

          {

               chin_type=input_tab[chin];

               state_bf=state_af;

               state_af=state_tran_tab[state_bf][chin_type];

               action_tab[state_bf][state_af](chin);

               i++;

          }

        }

    }

    int main()

    {

    char *input="a   b      c";

    translate(input);

    getchar();

    return 0;

    }

  • 相关阅读:
    SpringBoot启动过程中,候选类的过滤和加载
    Dubbo发布过程中,扩展点的加载
    Dubbo发布过程中,服务发布的实现
    Dubbo发布过程中,服务端调用过程
    SpringBean加载过程中,循环依赖的问题(一)
    Dubbo发布过程中,消费者的初始化过程
    DiscuzQ构建/发布小程序与H5前端
    Delphi写COM+的心得体会
    DBGridEh导出Excel等格式文件
    数据库直接通过bcp导出xml文件
  • 原文地址:https://www.cnblogs.com/cqpass/p/2268680.html
Copyright © 2011-2022 走看看