第96集:语法分析实战(三)—— 控制结构

核心知识点讲解

控制结构的文法设计

控制结构是编程语言中用于改变程序执行流程的语法结构。常见的控制结构包括:

  1. 条件语句:if-else 语句
  2. 循环语句:while 循环、for 循环、do-while 循环
  3. 跳转语句:break、continue、return 语句

设计控制结构的文法需要考虑以下因素:

  1. 结构完整性:确保控制结构的各个部分都能被正确识别
  2. 嵌套处理:支持控制结构的嵌套
  3. 优先级:控制结构与其他语句的优先级关系
  4. 歧义性:避免文法歧义,特别是 if-else 匹配问题

一个典型的控制结构文法:

statement → if_statement | while_statement | for_statement | assignment_statement | compound_statement
if_statement → if ( expression ) statement | if ( expression ) statement else statement
while_statement → while ( expression ) statement
for_statement → for ( expression_opt ; expression_opt ; expression_opt ) statement
compound_statement → { statement_list }
statement_list → statement | statement_list statement
expression_opt → /* 空 */ | expression

if 语句的分析

if 语句是最基本的控制结构之一,其文法设计需要特别注意 dangling else 问题(即 else 与哪个 if 匹配的问题)。在大多数编程语言中,采用 "else 与最近的未匹配 if 匹配" 的规则。

if 语句的分析步骤:

  1. 识别 if 关键字
  2. 解析条件表达式(括号内的部分)
  3. 解析 then 分支语句
  4. 可选地解析 else 分支语句

while 循环的分析

while 循环是一种基本的循环结构,其分析步骤:

  1. 识别 while 关键字
  2. 解析条件表达式(括号内的部分)
  3. 解析循环体语句

for 循环的分析

for 循环是一种更复杂的循环结构,通常包含初始化、条件和更新三个部分。其分析步骤:

  1. 识别 for 关键字
  2. 解析初始化表达式(第一个分号前的部分)
  3. 解析条件表达式(第一个分号和第二个分号之间的部分)
  4. 解析更新表达式(第二个分号后的部分)
  5. 解析循环体语句

实用案例分析

完整的控制结构分析器实现

下面是一个完整的控制结构分析器实现,包括 if 语句、while 循环、for 循环的分析,以及 AST 构建:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 词法分析器相关定义
typedef enum {
    TOKEN_IF,
    TOKEN_ELSE,
    TOKEN_WHILE,
    TOKEN_FOR,
    TOKEN_BREAK,
    TOKEN_CONTINUE,
    TOKEN_RETURN,
    TOKEN_ID,
    TOKEN_ASSIGN,
    TOKEN_PLUS,
    TOKEN_MINUS,
    TOKEN_MULT,
    TOKEN_DIV,
    TOKEN_LPAREN,
    TOKEN_RPAREN,
    TOKEN_LBRACE,
    TOKEN_RBRACE,
    TOKEN_SEMICOLON,
    TOKEN_NUMBER,
    TOKEN_LT,
    TOKEN_LE,
    TOKEN_GT,
    TOKEN_GE,
    TOKEN_EQ,
    TOKEN_NE,
    TOKEN_AND,
    TOKEN_OR,
    TOKEN_NOT,
    TOKEN_EOF,
    TOKEN_ERROR
} TokenType;

// AST节点类型
typedef enum {
    NODE_IF,
    NODE_WHILE,
    NODE_FOR,
    NODE_ASSIGN,
    NODE_COMPOUND,
    NODE_BREAK,
    NODE_CONTINUE,
    NODE_RETURN,
    NODE_BINARY,
    NODE_UNARY,
    NODE_CONSTANT,
    NODE_IDENTIFIER
} NodeType;

// AST节点结构
typedef struct ASTNode {
    NodeType type;
    union {
        struct {
            struct ASTNode *condition;
            struct ASTNode *then_branch;
            struct ASTNode *else_branch;
        } if_stmt;
        struct {
            struct ASTNode *condition;
            struct ASTNode *body;
        } while_stmt;
        struct {
            struct ASTNode *init;
            struct ASTNode *condition;
            struct ASTNode *update;
            struct ASTNode *body;
        } for_stmt;
        struct {
            char *name;
            struct ASTNode *value;
        } assign;
        struct {
            struct ASTNode *statements;
            struct ASTNode *next;
        } compound;
        struct {
            char op;
            struct ASTNode *left;
            struct ASTNode *right;
        } binary;
        struct {
            char op;
            struct ASTNode *expr;
        } unary;
        double constant;
        char *identifier;
    } value;
} ASTNode;

// 全局变量
TokenType current_token;
char id_name[100];
double number_value;
char* input;
int position;

// 词法分析函数
void get_token() {
    // 跳过空白字符
    while (input[position] && isspace(input[position])) {
        position++;
    }
    
    if (!input[position]) {
        current_token = TOKEN_EOF;
        return;
    }
    
    char c = input[position];
    
    // 识别关键字
    if (isalpha(c)) {
        int i = 0;
        char buf[100];
        while (input[position] && (isalnum(input[position]) || input[position] == '_')) {
            buf[i++] = input[position++];
        }
        buf[i] = '\0';
        
        if (strcmp(buf, "if") == 0) {
            current_token = TOKEN_IF;
        } else if (strcmp(buf, "else") == 0) {
            current_token = TOKEN_ELSE;
        } else if (strcmp(buf, "while") == 0) {
            current_token = TOKEN_WHILE;
        } else if (strcmp(buf, "for") == 0) {
            current_token = TOKEN_FOR;
        } else if (strcmp(buf, "break") == 0) {
            current_token = TOKEN_BREAK;
        } else if (strcmp(buf, "continue") == 0) {
            current_token = TOKEN_CONTINUE;
        } else if (strcmp(buf, "return") == 0) {
            current_token = TOKEN_RETURN;
        } else {
            strcpy(id_name, buf);
            current_token = TOKEN_ID;
        }
        return;
    }
    
    // 识别数字
    if (isdigit(c) || c == '.') {
        char num_str[100];
        int i = 0;
        while (input[position] && (isdigit(input[position]) || input[position] == '.')) {
            num_str[i++] = input[position++];
        }
        num_str[i] = '\0';
        number_value = atof(num_str);
        current_token = TOKEN_NUMBER;
        return;
    }
    
    // 识别运算符和标点符号
    switch (c) {
        case '=':
            position++;
            if (input[position] == '=') {
                current_token = TOKEN_EQ;
                position++;
            } else {
                current_token = TOKEN_ASSIGN;
            }
            break;
        case '+':
            current_token = TOKEN_PLUS;
            position++;
            break;
        case '-':
            current_token = TOKEN_MINUS;
            position++;
            break;
        case '*':
            current_token = TOKEN_MULT;
            position++;
            break;
        case '/':
            current_token = TOKEN_DIV;
            position++;
            break;
        case '(':
            current_token = TOKEN_LPAREN;
            position++;
            break;
        case ')':
            current_token = TOKEN_RPAREN;
            position++;
            break;
        case '{':
            current_token = TOKEN_LBRACE;
            position++;
            break;
        case '}':
            current_token = TOKEN_RBRACE;
            position++;
            break;
        case ';':
            current_token = TOKEN_SEMICOLON;
            position++;
            break;
        case '<':
            position++;
            if (input[position] == '=') {
                current_token = TOKEN_LE;
                position++;
            } else {
                current_token = TOKEN_LT;
            }
            break;
        case '>':
            position++;
            if (input[position] == '=') {
                current_token = TOKEN_GE;
                position++;
            } else {
                current_token = TOKEN_GT;
            }
            break;
        case '!':
            position++;
            if (input[position] == '=') {
                current_token = TOKEN_NE;
                position++;
            } else {
                current_token = TOKEN_NOT;
            }
            break;
        case '&':
            position++;
            if (input[position] == '&') {
                current_token = TOKEN_AND;
                position++;
            } else {
                current_token = TOKEN_ERROR;
            }
            break;
        case '|':
            position++;
            if (input[position] == '|') {
                current_token = TOKEN_OR;
                position++;
            } else {
                current_token = TOKEN_ERROR;
            }
            break;
        default:
            current_token = TOKEN_ERROR;
            position++;
            break;
    }
}

// AST节点创建函数
ASTNode* create_if_node(ASTNode *condition, ASTNode *then_branch, ASTNode *else_branch) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_IF;
    node->value.if_stmt.condition = condition;
    node->value.if_stmt.then_branch = then_branch;
    node->value.if_stmt.else_branch = else_branch;
    return node;
}

ASTNode* create_while_node(ASTNode *condition, ASTNode *body) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_WHILE;
    node->value.while_stmt.condition = condition;
    node->value.while_stmt.body = body;
    return node;
}

ASTNode* create_for_node(ASTNode *init, ASTNode *condition, ASTNode *update, ASTNode *body) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_FOR;
    node->value.for_stmt.init = init;
    node->value.for_stmt.condition = condition;
    node->value.for_stmt.update = update;
    node->value.for_stmt.body = body;
    return node;
}

ASTNode* create_assign_node(const char *name, ASTNode *value) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_ASSIGN;
    node->value.assign.name = strdup(name);
    node->value.assign.value = value;
    return node;
}

ASTNode* create_compound_node(ASTNode *statements) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_COMPOUND;
    node->value.compound.statements = statements;
    node->value.compound.next = NULL;
    return node;
}

ASTNode* create_break_node() {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_BREAK;
    return node;
}

ASTNode* create_continue_node() {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_CONTINUE;
    return node;
}

ASTNode* create_return_node(ASTNode *expr) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_RETURN;
    // 简化处理,实际应该存储返回表达式
    return node;
}

ASTNode* create_binary_node(char op, ASTNode *left, ASTNode *right) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_BINARY;
    node->value.binary.op = op;
    node->value.binary.left = left;
    node->value.binary.right = right;
    return node;
}

ASTNode* create_unary_node(char op, ASTNode *expr) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_UNARY;
    node->value.unary.op = op;
    node->value.unary.expr = expr;
    return node;
}

ASTNode* create_constant_node(double value) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_CONSTANT;
    node->value.constant = value;
    return node;
}

ASTNode* create_identifier_node(const char *name) {
    ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode));
    node->type = NODE_IDENTIFIER;
    node->value.identifier = strdup(name);
    return node;
}

// 释放AST
void free_ast(ASTNode *node) {
    if (!node) return;
    
    switch (node->type) {
        case NODE_IF:
            free_ast(node->value.if_stmt.condition);
            free_ast(node->value.if_stmt.then_branch);
            free_ast(node->value.if_stmt.else_branch);
            break;
        case NODE_WHILE:
            free_ast(node->value.while_stmt.condition);
            free_ast(node->value.while_stmt.body);
            break;
        case NODE_FOR:
            free_ast(node->value.for_stmt.init);
            free_ast(node->value.for_stmt.condition);
            free_ast(node->value.for_stmt.update);
            free_ast(node->value.for_stmt.body);
            break;
        case NODE_ASSIGN:
            free(node->value.assign.name);
            free_ast(node->value.assign.value);
            break;
        case NODE_COMPOUND:
            free_ast(node->value.compound.statements);
            free_ast(node->value.compound.next);
            break;
        case NODE_BINARY:
            free_ast(node->value.binary.left);
            free_ast(node->value.binary.right);
            break;
        case NODE_UNARY:
            free_ast(node->value.unary.expr);
            break;
        case NODE_IDENTIFIER:
            free(node->value.identifier);
            break;
        case NODE_BREAK:
        case NODE_CONTINUE:
        case NODE_RETURN:
        case NODE_CONSTANT:
            break;
    }
    
    free(node);
}

// 打印AST
void print_ast(ASTNode *node, int indent) {
    if (!node) return;
    
    for (int i = 0; i < indent; i++) {
        printf("  ");
    }
    
    switch (node->type) {
        case NODE_IF:
            printf("If\n");
            print_ast(node->value.if_stmt.condition, indent + 1);
            print_ast(node->value.if_stmt.then_branch, indent + 1);
            if (node->value.if_stmt.else_branch) {
                for (int i = 0; i < indent; i++) {
                    printf("  ");
                }
                printf("Else\n");
                print_ast(node->value.if_stmt.else_branch, indent + 1);
            }
            break;
        case NODE_WHILE:
            printf("While\n");
            print_ast(node->value.while_stmt.condition, indent + 1);
            print_ast(node->value.while_stmt.body, indent + 1);
            break;
        case NODE_FOR:
            printf("For\n");
            print_ast(node->value.for_stmt.init, indent + 1);
            print_ast(node->value.for_stmt.condition, indent + 1);
            print_ast(node->value.for_stmt.update, indent + 1);
            print_ast(node->value.for_stmt.body, indent + 1);
            break;
        case NODE_ASSIGN:
            printf("Assign: %s\n", node->value.assign.name);
            print_ast(node->value.assign.value, indent + 1);
            break;
        case NODE_COMPOUND:
            printf("Compound\n");
            print_ast(node->value.compound.statements, indent + 1);
            break;
        case NODE_BREAK:
            printf("Break\n");
            break;
        case NODE_CONTINUE:
            printf("Continue\n");
            break;
        case NODE_RETURN:
            printf("Return\n");
            break;
        case NODE_BINARY:
            printf("BinaryOp: %c\n", node->value.binary.op);
            print_ast(node->value.binary.left, indent + 1);
            print_ast(node->value.binary.right, indent + 1);
            break;
        case NODE_UNARY:
            printf("UnaryOp: %c\n", node->value.unary.op);
            print_ast(node->value.unary.expr, indent + 1);
            break;
        case NODE_CONSTANT:
            printf("Constant: %g\n", node->value.constant);
            break;
        case NODE_IDENTIFIER:
            printf("Identifier: %s\n", node->value.identifier);
            break;
    }
}

// 表达式分析
ASTNode* parse_expression();

ASTNode* parse_primary() {
    ASTNode *node = NULL;
    
    switch (current_token) {
        case TOKEN_NUMBER:
            node = create_constant_node(number_value);
            get_token();
            break;
        case TOKEN_ID:
            node = create_identifier_node(id_name);
            get_token();
            break;
        case TOKEN_LPAREN:
            get_token();
            node = parse_expression();
            if (current_token != TOKEN_RPAREN) {
                printf("错误: 缺少右括号\n");
                free_ast(node);
                return NULL;
            }
            get_token();
            break;
        case TOKEN_NOT:
            get_token();
            node = create_unary_node('!', parse_primary());
            break;
        case TOKEN_MINUS:
            get_token();
            node = create_unary_node('-', parse_primary());
            break;
        default:
            printf("错误: 意外的token\n");
            return NULL;
    }
    
    return node;
}

ASTNode* parse_factor() {
    ASTNode *node = parse_primary();
    
    while (current_token == TOKEN_MULT || current_token == TOKEN_DIV) {
        char op = (current_token == TOKEN_MULT) ? '*' : '/';
        get_token();
        ASTNode *right = parse_primary();
        node = create_binary_node(op, node, right);
    }
    
    return node;
}

ASTNode* parse_term() {
    ASTNode *node = parse_factor();
    
    while (current_token == TOKEN_PLUS || current_token == TOKEN_MINUS) {
        char op = (current_token == TOKEN_PLUS) ? '+' : '-';
        get_token();
        ASTNode *right = parse_factor();
        node = create_binary_node(op, node, right);
    }
    
    return node;
}

ASTNode* parse_relational() {
    ASTNode *node = parse_term();
    
    while (current_token == TOKEN_LT || current_token == TOKEN_LE || 
           current_token == TOKEN_GT || current_token == TOKEN_GE) {
        char op;
        switch (current_token) {
            case TOKEN_LT:
                op = '<';
                break;
            case TOKEN_LE:
                op = '≤';
                break;
            case TOKEN_GT:
                op = '>';
                break;
            case TOKEN_GE:
                op = '≥';
                break;
            default:
                op = ' ';
        }
        get_token();
        ASTNode *right = parse_term();
        node = create_binary_node(op, node, right);
    }
    
    return node;
}

ASTNode* parse_equality() {
    ASTNode *node = parse_relational();
    
    while (current_token == TOKEN_EQ || current_token == TOKEN_NE) {
        char op = (current_token == TOKEN_EQ) ? '=' : '≠';
        get_token();
        ASTNode *right = parse_relational();
        node = create_binary_node(op, node, right);
    }
    
    return node;
}

ASTNode* parse_logical_and() {
    ASTNode *node = parse_equality();
    
    while (current_token == TOKEN_AND) {
        get_token();
        ASTNode *right = parse_equality();
        node = create_binary_node('&&', node, right);
    }
    
    return node;
}

ASTNode* parse_logical_or() {
    ASTNode *node = parse_logical_and();
    
    while (current_token == TOKEN_OR) {
        get_token();
        ASTNode *right = parse_logical_and();
        node = create_binary_node('||', node, right);
    }
    
    return node;
}

ASTNode* parse_expression() {
    return parse_logical_or();
}

// 语句分析
ASTNode* parse_statement();

ASTNode* parse_compound_statement() {
    if (current_token != TOKEN_LBRACE) {
        printf("错误: 期望左大括号\n");
        return NULL;
    }
    
    get_token();
    ASTNode *statements = NULL;
    ASTNode *last_stmt = NULL;
    
    while (current_token != TOKEN_RBRACE && current_token != TOKEN_EOF) {
        ASTNode *stmt = parse_statement();
        if (!stmt) {
            break;
        }
        
        if (!statements) {
            statements = stmt;
            last_stmt = stmt;
        } else {
            // 简化处理,实际应该使用链表结构
            last_stmt = stmt;
        }
    }
    
    if (current_token != TOKEN_RBRACE) {
        printf("错误: 缺少右大括号\n");
        free_ast(statements);
        return NULL;
    }
    
    get_token();
    return create_compound_node(statements);
}

ASTNode* parse_if_statement() {
    if (current_token != TOKEN_IF) {
        printf("错误: 期望 if 关键字\n");
        return NULL;
    }
    
    get_token();
    if (current_token != TOKEN_LPAREN) {
        printf("错误: 缺少左括号\n");
        return NULL;
    }
    
    get_token();
    ASTNode *condition = parse_expression();
    if (!condition) {
        return NULL;
    }
    
    if (current_token != TOKEN_RPAREN) {
        printf("错误: 缺少右括号\n");
        free_ast(condition);
        return NULL;
    }
    
    get_token();
    ASTNode *then_branch = parse_statement();
    if (!then_branch) {
        free_ast(condition);
        return NULL;
    }
    
    ASTNode *else_branch = NULL;
    if (current_token == TOKEN_ELSE) {
        get_token();
        else_branch = parse_statement();
        if (!else_branch) {
            free_ast(condition);
            free_ast(then_branch);
            return NULL;
        }
    }
    
    return create_if_node(condition, then_branch, else_branch);
}

ASTNode* parse_while_statement() {
    if (current_token != TOKEN_WHILE) {
        printf("错误: 期望 while 关键字\n");
        return NULL;
    }
    
    get_token();
    if (current_token != TOKEN_LPAREN) {
        printf("错误: 缺少左括号\n");
        return NULL;
    }
    
    get_token();
    ASTNode *condition = parse_expression();
    if (!condition) {
        return NULL;
    }
    
    if (current_token != TOKEN_RPAREN) {
        printf("错误: 缺少右括号\n");
        free_ast(condition);
        return NULL;
    }
    
    get_token();
    ASTNode *body = parse_statement();
    if (!body) {
        free_ast(condition);
        return NULL;
    }
    
    return create_while_node(condition, body);
}

ASTNode* parse_for_statement() {
    if (current_token != TOKEN_FOR) {
        printf("错误: 期望 for 关键字\n");
        return NULL;
    }
    
    get_token();
    if (current_token != TOKEN_LPAREN) {
        printf("错误: 缺少左括号\n");
        return NULL;
    }
    
    get_token();
    ASTNode *init = NULL;
    if (current_token != TOKEN_SEMICOLON) {
        // 解析初始化表达式
        if (current_token == TOKEN_ID) {
            char var_name[100];
            strcpy(var_name, id_name);
            get_token();
            if (current_token == TOKEN_ASSIGN) {
                get_token();
                ASTNode *expr = parse_expression();
                if (expr) {
                    init = create_assign_node(var_name, expr);
                }
            }
        }
    }
    
    if (current_token != TOKEN_SEMICOLON) {
        printf("错误: 缺少分号\n");
        free_ast(init);
        return NULL;
    }
    
    get_token();
    ASTNode *condition = NULL;
    if (current_token != TOKEN_SEMICOLON) {
        condition = parse_expression();
        if (!condition) {
            free_ast(init);
            return NULL;
        }
    }
    
    if (current_token != TOKEN_SEMICOLON) {
        printf("错误: 缺少分号\n");
        free_ast(init);
        free_ast(condition);
        return NULL;
    }
    
    get_token();
    ASTNode *update = NULL;
    if (current_token != TOKEN_RPAREN) {
        // 解析更新表达式
        if (current_token == TOKEN_ID) {
            char var_name[100];
            strcpy(var_name, id_name);
            get_token();
            if (current_token == TOKEN_ASSIGN) {
                get_token();
                ASTNode *expr = parse_expression();
                if (expr) {
                    update = create_assign_node(var_name, expr);
                }
            }
        }
    }
    
    if (current_token != TOKEN_RPAREN) {
        printf("错误: 缺少右括号\n");
        free_ast(init);
        free_ast(condition);
        free_ast(update);
        return NULL;
    }
    
    get_token();
    ASTNode *body = parse_statement();
    if (!body) {
        free_ast(init);
        free_ast(condition);
        free_ast(update);
        return NULL;
    }
    
    return create_for_node(init, condition, update, body);
}

ASTNode* parse_assign_statement() {
    if (current_token != TOKEN_ID) {
        printf("错误: 期望变量名\n");
        return NULL;
    }
    
    char var_name[100];
    strcpy(var_name, id_name);
    get_token();
    
    if (current_token != TOKEN_ASSIGN) {
        printf("错误: 期望赋值运算符\n");
        return NULL;
    }
    
    get_token();
    ASTNode *expr = parse_expression();
    if (!expr) {
        return NULL;
    }
    
    if (current_token != TOKEN_SEMICOLON) {
        printf("错误: 缺少分号\n");
        free_ast(expr);
        return NULL;
    }
    
    get_token();
    return create_assign_node(var_name, expr);
}

ASTNode* parse_jump_statement() {
    ASTNode *node = NULL;
    
    if (current_token == TOKEN_BREAK) {
        node = create_break_node();
        get_token();
    } else if (current_token == TOKEN_CONTINUE) {
        node = create_continue_node();
        get_token();
    } else if (current_token == TOKEN_RETURN) {
        node = create_return_node(NULL);
        get_token();
    } else {
        printf("错误: 期望跳转语句\n");
        return NULL;
    }
    
    if (current_token != TOKEN_SEMICOLON) {
        printf("错误: 缺少分号\n");
        free_ast(node);
        return NULL;
    }
    
    get_token();
    return node;
}

ASTNode* parse_statement() {
    ASTNode *node = NULL;
    
    switch (current_token) {
        case TOKEN_IF:
            node = parse_if_statement();
            break;
        case TOKEN_WHILE:
            node = parse_while_statement();
            break;
        case TOKEN_FOR:
            node = parse_for_statement();
            break;
        case TOKEN_LBRACE:
            node = parse_compound_statement();
            break;
        case TOKEN_BREAK:
        case TOKEN_CONTINUE:
        case TOKEN_RETURN:
            node = parse_jump_statement();
            break;
        case TOKEN_ID:
            node = parse_assign_statement();
            break;
        default:
            printf("错误: 意外的token\n");
            break;
    }
    
    return node;
}

// 程序分析
ASTNode* parse_program() {
    ASTNode *statements = NULL;
    ASTNode *last_stmt = NULL;
    
    while (current_token != TOKEN_EOF) {
        ASTNode *stmt = parse_statement();
        if (!stmt) {
            break;
        }
        
        if (!statements) {
            statements = stmt;
            last_stmt = stmt;
        } else {
            // 简化处理,实际应该使用链表结构
            last_stmt = stmt;
        }
    }
    
    return statements;
}

// 主函数
int main() {
    char buffer[1000];
    
    printf("控制结构分析器\n");
    printf("支持的控制结构: if-else, while, for, break, continue, return\n");
    printf("输入程序,按回车分析 (输入 quit 退出)\n\n");
    
    while (1) {
        printf("输入: ");
        if (!fgets(buffer, sizeof(buffer), stdin)) {
            break;
        }
        
        // 处理输入
        buffer[strcspn(buffer, "\n")] = '\0';
        if (strcmp(buffer, "quit") == 0) {
            break;
        }
        if (strlen(buffer) == 0) {
            continue;
        }
        
        // 初始化
        input = buffer;
        position = 0;
        get_token();
        
        // 解析程序
        ASTNode *ast = parse_program();
        
        // 检查解析结果
        if (ast) {
            // 打印AST
            printf("AST:\n");
            print_ast(ast, 0);
            printf("\n");
            
            // 释放AST
            free_ast(ast);
        } else {
            printf("解析失败\n\n");
        }
    }
    
    printf("再见!\n");
    return 0;
}

运行效果

控制结构分析器
支持的控制结构: if-else, while, for, break, continue, return
输入程序,按回车分析 (输入 quit 退出)

输入: if (x > 0) { y = 1; } else { y = 0; }
AST:
If
  BinaryOp: >
    Identifier: x
    Constant: 0
  Compound
    Assign: y
      Constant: 1
  Else
    Compound
      Assign: y
        Constant: 0

输入: while (i < 10) { sum = sum + i; i = i + 1; }
AST:
While
  BinaryOp: <
    Identifier: i
    Constant: 10
  Compound
    Assign: sum
      BinaryOp: +
        Identifier: sum
        Identifier: i
    Assign: i
      BinaryOp: +
        Identifier: i
        Constant: 1

输入: for (i = 0; i < 10; i = i + 1) { printf(i); }
AST:
For
  Assign: i
    Constant: 0
  BinaryOp: <
    Identifier: i
    Constant: 10
  Assign: i
    BinaryOp: +
      Identifier: i
      Constant: 1
  Compound
    Identifier: printf

输入: if (a && b) { if (c) { break; } else { continue; } }
AST:
If
  BinaryOp: &&
    Identifier: a
    Identifier: b
  Compound
    If
      Identifier: c
      Compound
        Break
      Else
        Compound
          Continue

技术要点总结

  1. 控制结构文法的设计

    • 明确控制结构的各个组成部分
    • 支持嵌套结构
    • 避免文法歧义,特别是 if-else 匹配问题
  2. if 语句的分析

    • 正确处理条件表达式
    • 支持 then 分支和 else 分支
    • 实现 "else 与最近的未匹配 if 匹配" 规则
  3. 循环语句的分析

    • while 循环:处理条件表达式和循环体
    • for 循环:处理初始化、条件、更新和循环体
  4. 复合语句的分析

    • 处理花括号包围的语句块
    • 支持多个语句的顺序执行
  5. AST 的构建

    • 为不同类型的控制结构创建相应的 AST 节点
    • 正确表示控制结构的层次结构
    • 支持后续的语义分析和代码生成

代码优化建议

  1. 词法分析器优化

    • 使用状态机提高词法分析效率
    • 支持更多的关键字和运算符
    • 改进错误处理,提供更详细的词法错误信息
  2. 语法分析器优化

    • 实现更智能的错误恢复
    • 支持更复杂的控制结构(如 switch 语句)
    • 优化递归调用,避免栈溢出
  3. AST 优化

    • 添加位置信息,用于更精确的错误报告
    • 实现 AST 优化(如常量折叠)
    • 支持更多的语句类型
  4. 内存管理

    • 实现内存池,减少内存分配开销
    • 添加内存泄漏检测
    • 优化 AST 节点的内存布局
  5. 功能扩展

    • 支持 switch 语句
    • 支持 do-while 循环
    • 支持带标签的语句和 goto 语句
    • 支持更复杂的表达式和语句

高级应用技巧

作用域分析

在控制结构分析中,需要考虑作用域管理:

// 作用域结构
typedef struct Scope {
    // 符号表
    struct Scope *parent;
}

// 进入新作用域
void enter_scope() {
    // 创建新作用域并设为当前作用域
}

// 退出作用域
void exit_scope() {
    // 恢复到父作用域
}

// 解析复合语句时管理作用域
ASTNode* parse_compound_statement() {
    enter_scope();
    // 解析语句块
    exit_scope();
    // 返回复合语句节点
}

控制流分析

在 AST 构建后,可以进行控制流分析:

// 控制流分析
void analyze_control_flow(ASTNode *node) {
    if (!node) return;
    
    switch (node->type) {
        case NODE_IF:
            // 分析 if 语句的控制流
            analyze_control_flow(node->value.if_stmt.condition);
            analyze_control_flow(node->value.if_stmt.then_branch);
            analyze_control_flow(node->value.if_stmt.else_branch);
            break;
        case NODE_WHILE:
            // 分析 while 循环的控制流
            analyze_control_flow(node->value.while_stmt.condition);
            analyze_control_flow(node->value.while_stmt.body);
            break;
        case NODE_FOR:
            // 分析 for 循环的控制流
            analyze_control_flow(node->value.for_stmt.init);
            analyze_control_flow(node->value.for_stmt.condition);
            analyze_control_flow(node->value.for_stmt.update);
            analyze_control_flow(node->value.for_stmt.body);
            break;
        // 其他节点类型...
    }
}

代码生成

从 AST 生成目标代码:

// 代码生成
void generate_code(ASTNode *node) {
    if (!node) return;
    
    switch (node->type) {
        case NODE_IF:
            // 生成 if 语句的代码
            generate_code(node->value.if_stmt.condition);
            // 生成条件跳转
            generate_code(node->value.if_stmt.then_branch);
            // 生成 else 分支代码
            generate_code(node->value.if_stmt.else_branch);
            break;
        case NODE_WHILE:
            // 生成 while 循环的代码
            // 生成循环头部
            generate_code(node->value.while_stmt.condition);
            // 生成条件跳转
            generate_code(node->value.while_stmt.body);
            // 生成跳转回循环头部的代码
            break;
        // 其他节点类型...
    }
}

最佳实践总结

  1. 文法设计

    • 从简单到复杂,逐步构建文法
    • 明确控制结构的各个组成部分
    • 避免文法歧义,特别是 if-else 匹配问题
  2. 分析器实现

    • 分离词法分析和语法分析
    • 模块化设计,将不同功能分解为单独的函数
    • 实现详细的错误处理
  3. AST 构建

    • 为不同类型的控制结构创建相应的 AST 节点
    • 正确表示控制结构的层次结构
    • 支持后续的语义分析和代码生成
  4. 测试策略

    • 测试基本控制结构
    • 测试嵌套控制结构
    • 测试控制结构与其他语句的组合
    • 测试错误处理
  5. 性能优化

    • 优化词法分析和语法分析
    • 实现 AST 优化
    • 合理管理内存

通过本集的学习,你已经掌握了控制结构语法分析的核心技术,包括 if 语句、while 循环、for 循环等控制结构的文法设计和代码实现。这些技术不仅适用于控制结构,也是实现更复杂语法结构的基础。在实际应用中,你可以根据具体需求扩展和优化这个分析器,以支持更复杂的控制结构和语句类型。

« 上一篇 语法分析实战(二)—— 变量声明 下一篇 » 语法分析实战(四)—— 函数定义