#include "stdio.h"
#include "stdlib.h"
#include "string.h"
// 关键字数组结束标记
#define _KEY_WORD_END "waiting for your expanding"

char input[255];    // 存放用户输入的一串源程序
char token[255] = "";// 存放当前识别出来的单词(记号)
int p_input;        // input 的读取指针,记录读到哪个位置
int p_token;        // token 的写入指针
char ch;            // 当前读到的单个字符

// 关键字表
char* KEY_WORDS[] = {"begin", "if", "then", "while", "do", "end", _KEY_WORD_END};

// 函数声明
void scaner();      // 词法分析器:取出下一个单词
void factor();      // 因子分析
void term();        // 项分析
void statement();   // 语句分析
void expression();  // 表达式分析
void yucu();        // 语句串分析
void lrparser();    // 递归下降总入口,程序的语法分析主函数

int syn;            // 当前单词的类别编码
int kk;             // 错误标记,kk=1 代表已经出现错误

void main()
{
    kk = 0;
    printf("Enter Your words(end with #):");
    // 读取输入,直到遇到 #
    scanf("%[^#]s", input);
    printf("Your words:\n%s\n", input);

    scaner();        // 先读取第一个单词
    lrparser();      // 启动递归下降语法分析

    printf("\npress $ to exit:");
    scanf("%[^$]s", input);
}

// 语法分析入口:文法 program → begin 语句串 end
void lrparser()
{
    // syn == 1 代表读到 begin
    if (syn == 1)
    {
        scaner();
        yucu();      // 分析后面一长串语句
        if (syn == 6) // syn == 6 代表读到 end
        {
            scaner();
            // syn == 0 代表读到结束,并且没有报错
            if ((syn == 0) && (kk == 0))
                printf("\n success\n");
        }
        else
        {
            if (kk != 1)
            {
                printf("\n缺少'end'错误");
                kk = 1;
            }
        }
    }
    else
    {
        printf("begin错误");
        kk = 1;
    }
    return;
}

// 语句串:yucu → statement ; statement ; ...
void yucu()
{
    statement();               // 分析一条语句
    // syn == 26 是分号 ;
    while (syn == 26)
    {
        scaner();
        statement();
    }
    return;
}

// 语句:statement → 标识符 := 表达式
void statement()
{
    // syn == 10 代表标识符(变量名)
    if (syn == 10)
    {
        scaner();
        // syn == 18 代表赋值符号 :=
        if (syn == 18)
        {
            scaner();
            expression();   // 分析等号后面的表达式
        }
        else
        {
            printf("赋值号错误");
            kk = 1;
        }
    }
    else
    {
        printf("语句错误");
        kk = 1;
    }
    return;
}

// 表达式:expression → term ( +|- term )*
void expression()
{
    term();
    // syn13 加号 +,syn14 减号 -
    while (syn == 13 || syn == 14)
    {
        scaner();
        term();
    }
    return;
}

// 项:term → factor ( * | / factor )*
void term()
{
    factor();
    // syn15 乘号 *,syn16 除号 /
    while (syn == 15 || syn == 16)
    {
        scaner();
        factor();
    }
    return;
}

// 因子:factor → 标识符 | 数字 | ( 表达式 )
void factor()
{
    // syn10:标识符;syn11:数字
    if (syn == 10 || syn == 11)
        scaner();
    // syn27:左括号 (
    else if (syn == 27)
    {
        scaner();
        expression();
        // syn28:右括号 )
        if (syn == 28)
            scaner();
        else
        {
            printf("')'错误");
            kk = 1;
        }
    }
    else
    {
        printf("表达式错误");
        kk = 1;
    }
    return;
}

// 从 input 取出一个字符,并且移动指针
char m_getch()
{
    ch = input[p_input];
    p_input = p_input + 1;
    return (ch);
}

// 跳过空格、换行等空白字符
void getbc()
{
    while (ch == ' ' || ch == 10)
    {
        ch = input[p_input];
        p_input = p_input + 1;
    }
}

// 将当前字符拼接到 token 里面
void concat()
{
    token[p_token] = ch;
    p_token = p_token + 1;
    token[p_token] = '\0';
}

// 判断当前字符是不是英文字母
int letter()
{
    if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
        return 1;
    else
        return 0;
}

// 判断当前字符是不是数字
int digit()
{
    if (ch >= '0' && ch <= '9')
        return 1;
    else
        return 0;
}

// 判断 token 是否是关键字,是就返回编号,否则返回 10(标识符)
int reserve()
{
    int i = 0;
    while (strcmp(KEY_WORDS[i], _KEY_WORD_END))
    {
        if (!strcmp(KEY_WORDS[i], token))
        {
            return i + 1;
        }
        i = i + 1;
    }
    return 10;
}

// 指针回退一个字符(多读了,退回去)
void retract()
{
    p_input = p_input - 1;
}

// 数字转换函数,原版预留,这里没有实现
char* dtb()
{
    return NULL;
}

// 词法分析核心:识别单词,给出 syn 类别码
void scaner()
{
    p_token = 0;
    m_getch();
    getbc();

    // 如果是字母:标识符 / 关键字
    if (letter())
    {
        while (letter() || digit())
        {
            concat();
            m_getch();
        }
        retract();
        syn = reserve();
        return;
    }
    // 如果是数字
    else if (digit())
    {
        while (digit())
        {
            concat();
            m_getch();
        }
        retract();
        syn = 11;
        return;
    }
    // 如果是运算符、分隔符
    else
        switch (ch)
        {
        case '=':
            syn = 25;
            break;
        case '+':
            syn = 13;
            break;
        case '-':
            syn = 14;
            break;
        case '*':
            syn = 15;
            break;
        case '/':
            syn = 16;
            break;
        case '(':
            syn = 27;
            break;
        case ')':
            syn = 28;
            break;
        case ':':
            m_getch();
            if (ch == '=')
            {
                syn = 18;   // := 赋值符号
            }
            else
            {
                retract();
                syn = 17;
            }
            break;
        case ';':
            syn = 26;     // 分号
            break;
        case '>':
            m_getch();
            if (ch == '=')
            {
                syn = 24;
            }
            else
            {
                retract();
                syn = 23;
            }
            break;
        case '<':
            m_getch();
            if (ch == '=')
            {
                syn = 22;
                return;
            }
            retract();
            syn = 20;
            break;
        case '\0':
            syn = 0;      // 源程序结束标记
            break;
        default:
            syn = -1;     // 无法识别的非法字符
        }
    return;
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: