Experimento del principio del compilador (3) Diseño integral de análisis gramatical léxico

Declaración de derechos de autor: este artículo es un artículo original y los derechos de autor pertenecen a Geekerstar .

Enlace a este artículo: http://www.geekerstar.com/technology/105.html

A excepción de los artículos especialmente marcados, bienvenido a reimprimir, pero asegúrese de indicar la fuente, el formato es el anterior, gracias por su cooperación.

1. Información general

A través de un determinado lenguaje de alto nivel (como C / C ++, Java) para realizar la función de analizador léxico y sintáctico.

2 Objetivos experimentales

  1. Comprender y dominar los principios y métodos de análisis léxico y gramatical.

  2. Capaz de implementar programas de análisis léxico y gramatical en un idioma determinado.

  3. Tener una comprensión clara y completa de los conceptos básicos, principios y métodos de compilación, y ser capaz de utilizarlos correcta y hábilmente.

3 Descripción del experimento

3.1 Requisitos experimentales

Uso del programa de análisis léxico como método de subrutina del programa de análisis gramatical para realizar análisis léxico y gramatical.

Los requisitos específicos son los siguientes:

  • El programa de análisis léxico es una subrutina del programa de análisis de sintaxis.

  • Datos de entrada: segmento de programa.

  • Resultado de salida: resultado del análisis gramatical, incluida la lista de errores.

3.2 Descripción general de este experimento

El experimento escrito en C ++ analizador de sintaxis, sobre esta base, utiliza
procedimientos de análisis de estructura y verificación de sintaxis de descenso recursivo , secuencia de palabras del programa de análisis léxico proporcionado por el
análisis parcial . El lenguaje PL / 0 presenta características simples, claramente estructuradas, legibles, pero con el alto nivel general
debe ser parte del lenguaje de programación, por lo que el uso del lenguaje del compilador PL / 0 completamente a una encarnación del
compilador de lenguaje de alto nivel para lograr básico Método y tecnología, por lo que el lenguaje PL / 0 se utiliza para el análisis léxico.

4 Análisis técnico

4.1 Análisis léxico

Este experimento utiliza principalmente análisis de estructura de datos básicos, tecnología de programación C ++, principios de compilación, etc.
Los conceptos básicos de compilación se entienden comprendiendo dos partes: análisis léxico y análisis de sintaxis:

  • análisis léxico

Las reglas léxicas del analizador léxico identifican la fuente de cada token, cada token representa una
palabra de clase. La marca común de origen se puede clasificar en varias categorías: palabras clave, identificadores, literales y
símbolos especiales. La entrada del analizador léxico es el programa fuente y la salida es el flujo de tokens reconocido. La
tarea del analizador léxico es el carácter del flujo del archivo de origen en un flujo de tokens. Es la primera etapa del proceso de compilación. Su
tarea principal se describe de izquierda a derecha de cada descripción de cadena de caracteres de la fuente, identificada por una
palabra en la misma, y ​​convertirla en una salida de cadena de símbolos de la forma codificada de palabra interna, para analizar.

En pocas palabras, la gramática generalmente debe completar las siguientes tareas durante su trabajo:

(1) Identifique cada símbolo de palabra en el programa fuente y conviértalo en una forma de código interno;

(2) Eliminar caracteres en blanco inútiles, caracteres de retorno de carro y otros caracteres insustanciales;

(3) Eliminar comentarios;

(4) Realice una verificación léxica e informe los errores encontrados.

Además, dependiendo del flujo de trabajo compilado de la organización, parte del compilador durante el análisis léxico, sino también para
completar los identificadores identificados para iniciar sesión en el trabajo de la tabla de símbolos.

  • Analizando:

El análisis de sintaxis es el núcleo del proceso de compilación, el análisis de tareas es analizar el código fuente de acuerdo con las reglas de la
estructura gramatical gramatical, y en el análisis de la verificación de sintaxis del código fuente, si no hay errores de sintaxis,
entonces proporcione las estructuras gramaticales correctas, semánticas Prepárese para el análisis y la generación de código.

En la actualidad, existen muchos tipos de métodos de análisis gramatical, que se pueden dividir aproximadamente en dos categorías: de arriba hacia abajo y de abajo hacia arriba.
De arriba a abajo, se divide en método de análisis LL (1) y método de análisis de descenso recursivo. De abajo hacia arriba se divide en
gramática simple de prioridad única, gramática de precedencia de operadores, análisis LR (K). A continuación se presenta principalmente el
método de análisis ascendente LR (K).

El método de análisis ascendente también se denomina método de análisis de reducción de cambios. Su idea es realizar una cadena de símbolos de entrada
de escaneo de izquierda a derecha e ingresar el carácter uno por uno en una pila LIFO, el borde lateral en el análisis,
una vez que el identificador está formado por una oración de cadena de símbolos de pila, (que una manija corresponde a la parte derecha de la producción), a
una parte izquierda de la cadena de producción de símbolos gramaticales símbolo no terminal en lugar de la parte derecha correspondiente, que se denomina lugar de reducción.
Este proceso se repitió hasta que el análisis se redujo con éxito a la pila solo cuando el símbolo de inicio de la gramática, de hecho, se
reconoce como cadena de entrada es una oración en la gramática. De lo contrario, el análisis de fallas, representa una cadena de entrada de símbolo que no es la gramática de
la oración, que debe ser un error de sintaxis.

Basado en el conocimiento relevante de la compilación anterior combinado con el conocimiento del lenguaje de programación C ++ y algunas estructuras de datos para escribir un analizador léxico.

5 Diseño e implementación

5.1 Ideas de diseño

La preparación de un analizador sintáctico descendente recursivo, logro palabra por programa de análisis léxico proporcionado por la secuencia de
verificación de sintaxis y análisis estructural. Utilice C ++ para escribir un analizador sintáctico de descenso recursivo y
análisis de sintaxis del lenguaje PL / 0 . La idea central es comenzar desde el principio del estado, de acuerdo con la expansión gramatical, el análisis paso a paso del estado hasta que
se complete el análisis, si hay un estado de desajuste durante este período, que es un error de sintaxis, detenga el análisis. Por supuesto,
los mecanismos reales de recuperación de errores del analizador tienen que encontrar otros errores gramaticales. Es decir, un periódico
informó más errores de sintaxis. También para lograr el análisis, primero debe tener un análisis léxico, utilizando el
resultado del análisis léxico del análisis.

El BNF ampliado se expresa de la siguiente manera:

La preparación de un analizador sintáctico descendente recursivo, logro palabra por programa de análisis léxico proporcionado por la secuencia de
verificación de sintaxis y análisis estructural.

Utilice C ++ para escribir un programa de análisis de descenso recursivo y realice análisis gramaticales en lenguaje PL / 0.

\ <programa> :: = comenzar \ <cadena de instrucciones> fin

\ <cadena de declaración>: = \ <declaración> {; \ <declaración>}

\ <declaración>: = \ <declaración de asignación>

\ <instrucción de asignación> :: = ID: = \ <expresión>

\ <expresión> :: = \ <elemento> {+ \ <elemento> | - \ <elemento>}

\ <item> :: = \ <factor> {* \ <factor> | / \ <factor>

\ <factor> :: = ID | NUM | (\ <expresión>)

Ingrese la cadena de palabras y termine con "#". Si es una oración gramaticalmente correcta, generará un mensaje de éxito e
imprimirá "¡Análisis de sintaxis exitoso !", De lo contrario, generará "Error de análisis de sintaxis (motivo del error)".

P.ej:

Ingrese begin a: = 4; b: = 2 * 3; c: = a + b end #

¡El análisis de sintaxis de salida es exitoso!

Ingrese x: = a + b * c end #

Falta la salida begin!

Símbolo de palabra Código de especie
Empezar 1
Si 2
Luego 3
Mientras 4
Hacer 5
Fin 6
Identificador 10
digital 20
+ 13
- 14
* 15
/ dieciséis
: 17
: = 18
\ < 20
\ <> 21
\ <= 22
> 23
> = 24
= 25
; 26
( 27
) 28
# 0

5.2 Método de implementación

Este experimento utiliza codificación C ++, en la que se escriben principalmente las siguientes funciones y funciones:

Void cifa() //词法分析

Void fun_yufa() //判断语法是否有错误

Void fun_op() //处理运算符(\*和/)

Void exp() //处理运算符(+和-)

Void fun_yuju() //判断是否有语句错误(:=)

Void fun_end() //判断程序是否结束

Void yufa() //采用递归下降的语法分析

Entre ellos, cifa () realiza análisis léxico y llama a yufa () para realizar análisis gramatical con los resultados del análisis léxico.

833655145ca0bdfcc389a76dd9b2e8d3.png

Figura 1 Parte del código de análisis léxico

4a32ed6124fc05f333997cecf27a248f.png

Figura 2 Parte de la función de análisis de sintaxis

5.3 Caso de prueba

Proyecto / software Analizador léxico Versión del programa V1.0
Nombre del módulo de función Módulo de análisis léxico Editor XX
Número de caso de uso T1.0 Tiempo de preparación 207.11.20
Caracteristicas Análisis y juicio de la definición de la gramática léxica
Fines de prueba Determinar si la gramática léxica es correcta.
Datos de prueba 1 : comienza a: = 3; b: = 2 * 4; c: = a + b; final # 2 : a: = 3; b: = 2 * 4; c: = a + b; final # 3: comienza a: = 3; b: = 2 * 4; c: = a + b; #
Caso de prueba Descripción de la operación Código Resultado deseado resultados actuales Estado de prueba
1 Ingrese el primer código comenzar a: = 3; b: = 2 * 4; c: = a + b; final # La sintaxis es correcta La sintaxis es correcta bueno
2 Ingrese el segundo código a:=3;b:=2*4;c:=a+b; end # 缺少Begin 缺少begin 良好
3 输入第三段代码 begin a:=3;b:=2*4;c:=a+b; # 缺少结束符 缺少结束符 良好

5.4 实验结果及分析

输入一段PL/0语言,比如输入:begin a:=3;b:=2*4;c:=a+b; end #

此段代码语法是正确的,所以经过词法语法分析输出的结果应该是:语
法分析正确!如下图所示:

Gráfico de resultado del análisis léxico

图3 实验结果1

当我们漏掉begin,语法分析器应该检测出并输出:缺少begin!如下图:

El resultado final de la prueba

图4 实验结果2

6 总结

经过这次实验,我对编译原理有了更近一步的理解,让我知道了词法分
析的功能是输出把它组织成单个程序,让我了解到如何设计、编写并调试词
法分析程序,对语法规则有明确的定义;编写的分析程序能够进行正确的语
法分析;对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误
提示,保证顺利完成语法分析过程,并且通过实验的练习,加强了对基本概
念的理解和应用,对以后的学习也打下了基础。目前程序也存在着少量不足
之处,主要是语法分析部分还有不完善的地方,错误报告也有待改进,希望
在经过进一步的学习后,这些问题能逐步解决。

7 参考文献

1.互联网:百度,CSDN博客。

2.教材:《编译技术》张莉 高等教育出版社。

3.教材:C++ primer plus(第六版)

8 代码展示

#include "cstdio"
#include "string"
#include "iostream"
#include "algorithm"
#include "cstring"
using namespace std;

char str[1000];            //从键盘输入
char bzf[8];      //判断是否是关键字
char ch;
char *keyword[6]={
   
   "begin","if","then","while","do","end"};
int num,p,m,n,sum;
int x;


void cifa()   //词法分析
{
    sum=0;
    for(m=0;m<8;m++)
        bzf[m++]=NULL;
    m=0;
    ch=str[p++];
    while(ch==' ')       //去掉空格
        ch=str[p++];
    if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))  //标识符
    {
        while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9')))
        {
            bzf[m++]=ch;
            ch=str[p++];
        }
        p--;
        num=10;
        bzf[m++]='\0';
        for(n=0;n<6;n++)
        if(strcmp(bzf,keyword[n])==0)
        {
            num=n+1;
            break;
        }
    }
    else if((ch>='0')&&(ch<='9'))  //数字
    {
        while((ch>='0')&&(ch<='9'))
        {
            sum=sum*10+ch-'0';
            ch=str[p++];
        }
        p--;
        num=11;
    }
    else
    switch(ch)     //符号
    {
        case '<':
            m=0;
            ch=str[p++];
            if(ch=='>')
            {
                num=21;
            }
            else if(ch=='=')
            {
                num=22;
            }
            else
            {
                num=20;
                p--;
            }
        break;

        case '>':
            m=0;
            ch=str[p++];
            if(ch=='=')
            {
                num=24;
            }
            else
            {
                num=23;
                p--;
            }
        break;

        case ':':
            m=0;
            ch=str[p++];
            if(ch=='=')
            {
                num=18;
            }
            else
            {
                num=17;
                p--;
            }
            break;

        case '+':
            num=13;
        break;

        case '-':
            num=14;
        break;

        case '*':
            num=15;
        break;

        case '/':
            num=16;
        break;

        case '(':
            num=27;
        break;

        case ')':
            num=28;
        break;

        case '=':
            num=25;
        break;

        case ';':
            num=26;
        break;

        case '#':
            num=0;
        break;

        default:
            num=-1;
        break;
    }
}
void term();
void exp();
void fun_yufa()   //判断语法是否错误
{
    if((num==10)||(num==11))//关键字,数字
    {
        cifa();
    }
    else if(num==27)
    {
        cifa();
        exp();

        if(num==28)
        {
            cifa();          /*读下一个单词符号*/
        }
        else
        {
            printf("缺少‘(’\n");
            x=1;
        }
    }
    else
    {
        printf("语法错误\n");
        x=1;
    }
    return;
}
void fun_op()  //处理运算符
{
    fun_yufa();
    while((num==15)||(num==16))//  '*'和'/'
    {
        cifa();             /*读下一个单词符号*/
        fun_yufa();
    }
    return;
}

void exp()   //处理运算符
{
    fun_op();
    while((num==13)||(num==14))   //+和-
    {
        cifa();               /*读下一个单词符号*/
        fun_op();
    }

    return;
}


void fun_yuju()  //判断是否有语句错误
{
    if(num==10)
    {
        cifa();        /*读下一个单词符号*/
        if(num==18)
        {
            cifa();      /*读下一个单词符号*/
            exp();              }
        else
        {
            printf("':='错误\n");
            x=1;
        }
    }
    else
    {
        printf("语法错误!\n");
        x=1;
    }

    return;
}

void fun_end()  //判断程序结束的标志
{
    fun_yuju();         /*调用函数statement();*/

    while(num==26)
    {
        cifa();          /*读下一个单词符号*/
        if(num!=6)
            fun_yuju();          /*调用函数statement();*/
    }

    return;
}

void yufa()  //递归下降语法分析
{
    if(num==1)
    {
        cifa();
        fun_end();
        if(num==6)
        {
            cifa();
            if((num==0)&&(x==0))
            printf("语法分析正确!\n");
        }
        else
        {
            if(x!=1) printf("缺少end!\n");
            x=1;
        }
    }
    else
    {
        printf("缺少begin!\n");
        x=1;
    }

    return;
}

int main()
{
    p=x=0;
    printf("请输入一段语句以#结束: \n");
    do
    {
        scanf("%c",&ch);
        str[p++]=ch;
    }while(ch!='#');
    p=0;
    cifa();
    yufa();
    return 0;
}

版权声明:本文为原创文章,版权归 Geekerstar 所有。

本文链接:http://www.geekerstar.com/technology/105.html

除了有特殊标注文章外欢迎转载,但请务必标明出处,格式如上,谢谢合作。

Supongo que te gusta

Origin blog.csdn.net/geekerstar/article/details/79518312
Recomendado
Clasificación