求助deepsee 生成语法树代码
配套讲故事的视频
在搜抽象语法树代码未果走投无路询问deepsee 意外得到靠谱代码借助别人家的PPT左右对照意外发现原来是连续递归和二叉树_哔哩哔哩_bilibili
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>// 自定义字符串复制函数
char* string_copy(const char* s, size_t n) {if (n == 0) return NULL;char* result = (char*)malloc(n + 1);if (!result) {perror("malloc failed");exit(EXIT_FAILURE);}memcpy(result, s, n);result[n] = '\0';return result;
}// AST节点类型
typedef enum {NODE_if,NODE_WHILE,NODE_BINARY_OP,NODE_INTEGER,NODE_IDENTIFIER,NODE_COMPOUND,NODE_ASSIGNMENT
} NodeType;// 二元运算符类型
typedef enum {OP_LT, // <OP_GT, // >OP_EQ, // ==OP_NE, // !=OP_LE, // <=OP_GE // >=
} BinaryOp;// AST节点结构
typedef struct ASTNode {NodeType type;union {// while节点struct {struct ASTNode *condition;struct ASTNode *body;} while_stmt;struct {struct ASTNode *condition;struct ASTNode *body;} if_stmt;// 二元操作节点struct {BinaryOp op;struct ASTNode *left;struct ASTNode *right;} binary_op;// 整数字面量int integer_value;// 标识符char *identifier;// 复合语句(代码块)struct {struct ASTNode **statements;int count;} compound;// 赋值语句struct {char *variable;struct ASTNode *value;} assignment;} data;
} ASTNode;// 节点创建函数
ASTNode *create_while_node(ASTNode *condition, ASTNode *body) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_WHILE;node->data.while_stmt.condition = condition;node->data.while_stmt.body = body;// node->data.integer_value=10;return node;
}ASTNode *create_if_node(ASTNode *condition, ASTNode *body) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_if;node->data.while_stmt.condition = condition;node->data.while_stmt.body = body;// node->data.integer_value=10;return node;
}ASTNode *create_binary_op_node(BinaryOp op, ASTNode *left, ASTNode *right) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_BINARY_OP;node->data.binary_op.op = op;node->data.binary_op.left = left;node->data.binary_op.right = right;return node;
}ASTNode *create_integer_node(int value) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_INTEGER;node->data.integer_value = value;return node;
}ASTNode *create_identifier_node(const char *name) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_IDENTIFIER;node->data.identifier = strdup(name);if (!node->data.identifier) {perror("strdup failed");exit(EXIT_FAILURE);}return node;
}ASTNode *create_compound_node(ASTNode **statements, int count) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_COMPOUND;node->data.compound.statements = statements;node->data.compound.count = count;return node;
}ASTNode *create_assignment_node(const char *variable, ASTNode *value) {ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));if (!node) {perror("malloc failed");exit(EXIT_FAILURE);}node->type = NODE_ASSIGNMENT;node->data.assignment.variable = strdup(variable);if (!node->data.assignment.variable) {perror("strdup failed");exit(EXIT_FAILURE);}node->data.assignment.value = value;return node;
}// 词法分析器
typedef struct {const char *input;int pos;int len;
} Lexer;typedef enum {TOKEN_IF,TOKEN_WHILE,TOKEN_LPAREN,TOKEN_RPAREN,TOKEN_LBRACE,TOKEN_RBRACE,TOKEN_LT,TOKEN_GT,TOKEN_EQ,TOKEN_NE,TOKEN_LE,TOKEN_GE,TOKEN_ASSIGN, // 赋值运算符 =TOKEN_IDENTIFIER,TOKEN_INTEGER,TOKEN_SEMICOLON,TOKEN_EOF,TOKEN_ERROR
} TokenType;typedef struct {TokenType type;char *value;
} Token;Token get_next_token(Lexer *lexer) {// 跳过空白字符while (lexer->pos < lexer->len && (lexer->input[lexer->pos] == ' ' || lexer->input[lexer->pos] == '\n' ||lexer->input[lexer->pos] == '\t')) {lexer->pos++;}// 检查是否到达输入末尾if (lexer->pos >= lexer->len) {return (Token){TOKEN_EOF, NULL};}char current = lexer->input[lexer->pos];// 标识符或关键字if (isalpha(current)) {int start = lexer->pos;while (lexer->pos < lexer->len && (isalnum(lexer->input[lexer->pos]) || lexer->input[lexer->pos] == '_')) {lexer->pos++;}int length = lexer->pos - start;char *value = string_copy(&lexer->input[start], length);// 检查是否是关键字if (strncmp(value, "while", 5) == 0 && length == 5) {free(value);printf("get_next_token find while\n");return (Token){TOKEN_WHILE, NULL};}else if (strncmp(value, "if", 2) == 0 && length == 2) {free(value);printf("get_next_token find while\n");return (Token){TOKEN_IF, NULL};}return (Token){TOKEN_IDENTIFIER, value};}// 数字if (isdigit(current)) {int start = lexer->pos;while (lexer->pos < lexer->len && isdigit(lexer->input[lexer->pos])) {lexer->pos++;}int length = lexer->pos - start;char *value = string_copy(&lexer->input[start], length);return (Token){TOKEN_INTEGER, value};}// 运算符和标点符号switch (current) {case '(':lexer->pos++;return (Token){TOKEN_LPAREN, NULL};case ')':lexer->pos++;return (Token){TOKEN_RPAREN, NULL};case '{':lexer->pos++;return (Token){TOKEN_LBRACE, NULL};case '}':lexer->pos++;return (Token){TOKEN_RBRACE, NULL};case ';':lexer->pos++;return (Token){TOKEN_SEMICOLON, NULL};case '=':lexer->pos++;if (lexer->pos < lexer->len && lexer->input[lexer->pos] == '=') {lexer->pos++;return (Token){TOKEN_EQ, NULL};}return (Token){TOKEN_ASSIGN, NULL};case '<':lexer->pos++;if (lexer->pos < lexer->len && lexer->input[lexer->pos] == '=') {lexer->pos++;return (Token){TOKEN_LE, NULL};}return (Token){TOKEN_LT, NULL};case '>':lexer->pos++;if (lexer->pos < lexer->len && lexer->input[lexer->pos] == '=') {lexer->pos++;return (Token){TOKEN_GE, NULL};}return (Token){TOKEN_GT, NULL};case '!':lexer->pos++;if (lexer->pos < lexer->len && lexer->input[lexer->pos] == '=') {lexer->pos++;return (Token){TOKEN_NE, NULL};}// 错误处理:! 后面没有 = 的情况fprintf(stderr, "Error: Expected '=' after '!'\n");return (Token){TOKEN_ERROR, NULL};}// 未知字符fprintf(stderr, "Error: Unexpected character '%c'\n", current);return (Token){TOKEN_ERROR, NULL};
}// 解析简单表达式(标识符或整数)
ASTNode *parse_simple_expression(Lexer *lexer, Token *current_token) {if (current_token->type == TOKEN_IDENTIFIER) {ASTNode *node = create_identifier_node(current_token->value);free(current_token->value);*current_token = get_next_token(lexer);return node;} else if (current_token->type == TOKEN_INTEGER) {int value = atoi(current_token->value);free(current_token->value);*current_token = get_next_token(lexer);return create_integer_node(value);}fprintf(stderr, "Error: Expected identifier or integer in expression\n");exit(EXIT_FAILURE);
}// 解析赋值语句
ASTNode *parse_assignment(Lexer *lexer, Token *current_token) {if (current_token->type != TOKEN_IDENTIFIER) {fprintf(stderr, "Error: Expected identifier at start of assignment\n");exit(EXIT_FAILURE);}char *var_name = current_token->value;*current_token = get_next_token(lexer);if (current_token->type != TOKEN_ASSIGN) {fprintf(stderr, "Error: Expected '=' in assignment\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);ASTNode *value = parse_simple_expression(lexer, current_token);return create_assignment_node(var_name, value);
}// 解析表达式(比较表达式)
ASTNode *parse_expression(Lexer *lexer, Token *current_token) {ASTNode *left = parse_simple_expression(lexer, current_token);// 检查比较运算符BinaryOp op;switch (current_token->type) {case TOKEN_LT: op = OP_LT; break;case TOKEN_GT: op = OP_GT; break;case TOKEN_EQ: op = OP_EQ; break;case TOKEN_NE: op = OP_NE; break;case TOKEN_LE: op = OP_LE; break;case TOKEN_GE: op = OP_GE; break;default:fprintf(stderr, "Error: Expected comparison operator\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);ASTNode *right = parse_simple_expression(lexer, current_token);return create_binary_op_node(op, left, right);
}// 解析语句
ASTNode *parse_statement(Lexer *lexer, Token *current_token);// 解析复合语句(代码块)
ASTNode *parse_compound_statement(Lexer *lexer, Token *current_token) {if (current_token->type != TOKEN_LBRACE) {fprintf(stderr, "Error: Expected '{' at start of compound statement\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);ASTNode **statements = NULL;int count = 0;int capacity = 0;while (current_token->type != TOKEN_RBRACE && current_token->type != TOKEN_EOF) {if (count >= capacity) {capacity = capacity == 0 ? 4 : capacity * 2;statements = (ASTNode**)realloc(statements, capacity * sizeof(ASTNode *));if (!statements) {perror("realloc failed");exit(EXIT_FAILURE);}}statements[count] = parse_statement(lexer, current_token);count++;// 检查语句结束符if (current_token->type == TOKEN_SEMICOLON) {*current_token = get_next_token(lexer);} else if (current_token->type != TOKEN_RBRACE) {fprintf(stderr, "Error: Expected ';' after statement\n");exit(EXIT_FAILURE);}}if (current_token->type != TOKEN_RBRACE) {fprintf(stderr, "Error: Expected '}' to close compound statement\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);return create_compound_node(statements, count);
}// 解析语句
ASTNode *parse_statement(Lexer *lexer, Token *current_token) {if (current_token->type == TOKEN_WHILE) {*current_token = get_next_token(lexer);if (current_token->type != TOKEN_LPAREN) {fprintf(stderr, "Error: Expected '(' after 'while'\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);ASTNode *condition = parse_expression(lexer, current_token);if (current_token->type != TOKEN_RPAREN) {fprintf(stderr, "Error: Expected ')' after while condition\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);// 解析循环体(可能是单条语句或复合语句)ASTNode *body;if (current_token->type == TOKEN_LBRACE) {body = parse_compound_statement(lexer, current_token);} else {body = parse_statement(lexer, current_token);}return create_while_node(condition, body);} else if (current_token->type == TOKEN_IDENTIFIER) {// 赋值语句return parse_assignment(lexer, current_token);} else if (current_token->type == TOKEN_LBRACE) {// 复合语句return parse_compound_statement(lexer, current_token);}else if (current_token->type == TOKEN_IF) {*current_token = get_next_token(lexer);if (current_token->type != TOKEN_LPAREN) {fprintf(stderr, "Error: Expected '(' after 'if'\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);ASTNode *condition = parse_expression(lexer, current_token);if (current_token->type != TOKEN_RPAREN) {fprintf(stderr, "Error: Expected ')' after if condition\n");exit(EXIT_FAILURE);}*current_token = get_next_token(lexer);// 解析循环体(可能是单条语句或复合语句)ASTNode *body;if (current_token->type == TOKEN_LBRACE) {body = parse_compound_statement(lexer, current_token);} else {body = parse_statement(lexer, current_token);}return create_if_node(condition, body);} fprintf(stderr, "Error: Unexpected token in statement\n");exit(EXIT_FAILURE);
}// 主解析函数
ASTNode *parse(const char *input) {Lexer lexer;lexer.input = input;lexer.pos = 0;lexer.len = strlen(input);Token current_token = get_next_token(&lexer);if (current_token.type == TOKEN_ERROR) {return NULL;}return parse_statement(&lexer, ¤t_token);
}// AST打印函数
void print_ast(ASTNode *node, int indent) {if (!node) return;for (int i = 0; i < indent; i++) printf(" ");switch (node->type) {case NODE_WHILE:printf("WHILE\n");print_ast(node->data.while_stmt.condition, indent + 1);print_ast(node->data.while_stmt.body, indent + 1);break;case NODE_if:printf("IF\n");print_ast(node->data.if_stmt.condition, indent + 1);print_ast(node->data.if_stmt.body, indent + 1);break;case NODE_BINARY_OP:printf("BINARY_OP(");switch (node->data.binary_op.op) {case OP_LT: printf("<"); break;case OP_GT: printf(">"); break;case OP_EQ: printf("=="); break;case OP_NE: printf("!="); break;case OP_LE: printf("<="); break;case OP_GE: printf(">="); break;}printf(")\n");print_ast(node->data.binary_op.left, indent + 1);print_ast(node->data.binary_op.right, indent + 1);break;case NODE_INTEGER:printf("INTEGER(%d)\n", node->data.integer_value);break;case NODE_IDENTIFIER:printf("IDENTIFIER(%s)\n", node->data.identifier);break;case NODE_COMPOUND:printf("COMPOUND_STATEMENT\n");for (int i = 0; i < node->data.compound.count; i++) {print_ast(node->data.compound.statements[i], indent + 1);}break;case NODE_ASSIGNMENT:printf("ASSIGNMENT: %s\n", node->data.assignment.variable);print_ast(node->data.assignment.value, indent + 1);break;}
}// 释放AST内存
void free_ast(ASTNode *node) {if (node == NULL) return;switch (node->type) {case NODE_WHILE:free_ast(node->data.while_stmt.condition);free_ast(node->data.while_stmt.body);break;case NODE_BINARY_OP:free_ast(node->data.binary_op.left);free_ast(node->data.binary_op.right);break;case NODE_IDENTIFIER:free(node->data.identifier);break;case NODE_COMPOUND:for (int i = 0; i < node->data.compound.count; i++) {free_ast(node->data.compound.statements[i]);}free(node->data.compound.statements);break;case NODE_ASSIGNMENT:free(node->data.assignment.variable);free_ast(node->data.assignment.value);break;default:break;}free(node);
}int main() {const char *code = "while (x < 10) { y = 5; z = 20; if (x < 10) { y = 5; z = 20; if (x < 10) { c = 8 ; }} }";printf("Parsing code: %s\n", code);ASTNode *ast = parse(code);if (!ast) {printf("Parsing failed\n");return 1;}printf("\nGenerated AST:\n");print_ast(ast, 0);free_ast(ast);return 0;
}