init basic
This commit is contained in:
commit
09299e339c
46
ccompiler/frontend/Makefile
Normal file
46
ccompiler/frontend/Makefile
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# 编译器设置
|
||||||
|
CC = gcc
|
||||||
|
AR = ar
|
||||||
|
CFLAGS = -g
|
||||||
|
|
||||||
|
# 源文件路径
|
||||||
|
LEXER_DIR = ./lexer
|
||||||
|
PARSER_DIR = ./parser
|
||||||
|
AST_DIR = ./parser/ast
|
||||||
|
SYMTAB_DIR = ./parser/symtab
|
||||||
|
|
||||||
|
# 源文件列表
|
||||||
|
SRCS = \
|
||||||
|
frontend.c \
|
||||||
|
$(LEXER_DIR)/lexer.c \
|
||||||
|
$(PARSER_DIR)/parser.c \
|
||||||
|
$(AST_DIR)/ast.c \
|
||||||
|
$(AST_DIR)/block.c \
|
||||||
|
$(AST_DIR)/decl.c \
|
||||||
|
$(AST_DIR)/expr.c \
|
||||||
|
$(AST_DIR)/func.c \
|
||||||
|
$(AST_DIR)/program.c \
|
||||||
|
$(AST_DIR)/stmt.c \
|
||||||
|
$(AST_DIR)/term.c \
|
||||||
|
$(SYMTAB_DIR)/hashmap.c \
|
||||||
|
$(SYMTAB_DIR)/scope.c \
|
||||||
|
$(SYMTAB_DIR)/symtab.c \
|
||||||
|
|
||||||
|
# 生成目标文件列表
|
||||||
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
|
# 最终目标
|
||||||
|
TARGET = libfrontend.a
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(AR) rcs $@ $^
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
18
ccompiler/frontend/frontend.c
Normal file
18
ccompiler/frontend/frontend.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "lexer/lexer.h"
|
||||||
|
#include "parser/symtab/symtab.h"
|
||||||
|
#include "frontend.h"
|
||||||
|
|
||||||
|
struct ASTNode* frontend(const char* file, void* stream, sread_fn sread) {
|
||||||
|
struct Lexer lexer;
|
||||||
|
init_lexer(&lexer, file, stream, sread);
|
||||||
|
|
||||||
|
struct SymbolTable symtab;
|
||||||
|
init_symtab(&symtab);
|
||||||
|
|
||||||
|
struct Parser parser;
|
||||||
|
init_parser(&parser, &lexer, &symtab);
|
||||||
|
parse_prog(&parser);
|
||||||
|
|
||||||
|
// TODO Free the resourse
|
||||||
|
return parser.root;
|
||||||
|
}
|
24
ccompiler/frontend/frontend.h
Normal file
24
ccompiler/frontend/frontend.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef __FRONTEND_H__
|
||||||
|
#define __FRONTEND_H__
|
||||||
|
|
||||||
|
#ifndef error
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define STD_LIBRARY
|
||||||
|
#define error(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0)
|
||||||
|
#endif
|
||||||
|
#ifndef warn
|
||||||
|
#include <stdio.h>
|
||||||
|
#define STD_LIBRARY
|
||||||
|
#define warn(...) do { fprintf(stdout, __VA_ARGS__); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define xmalloc(size) malloc(size)
|
||||||
|
|
||||||
|
#include "parser/parser.h"
|
||||||
|
#include "parser/ast/ast.h"
|
||||||
|
|
||||||
|
typedef int (*sread_fn)(void *dst_buf, int dst_size, int elem_size, int count, void *stream);
|
||||||
|
struct ASTNode* frontend(const char* file, void* stream, sread_fn sread);
|
||||||
|
|
||||||
|
#endif
|
5
ccompiler/frontend/lexer/README.md
Normal file
5
ccompiler/frontend/lexer/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# 词法分析
|
||||||
|
|
||||||
|
参考LCC的此分析部分
|
||||||
|
|
||||||
|
主要使用 LL(n) 硬编码查找token
|
523
ccompiler/frontend/lexer/lexer.c
Normal file
523
ccompiler/frontend/lexer/lexer.c
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
/**
|
||||||
|
* 仿照LCCompiler的词法分析部分
|
||||||
|
*
|
||||||
|
* 如下为LCC的README in 2025.2
|
||||||
|
This hierarchy is the distribution for lcc version 4.2.
|
||||||
|
|
||||||
|
lcc version 3.x is described in the book "A Retargetable C Compiler:
|
||||||
|
Design and Implementation" (Addison-Wesley, 1995, ISBN 0-8053-1670-1).
|
||||||
|
There are significant differences between 3.x and 4.x, most notably in
|
||||||
|
the intermediate code. For details, see
|
||||||
|
https://drh.github.io/lcc/documents/interface4.pdf.
|
||||||
|
|
||||||
|
VERSION 4.2 IS INCOMPATIBLE WITH EARLIER VERSIONS OF LCC. DO NOT
|
||||||
|
UNLOAD THIS DISTRIBUTION ON TOP OF A 3.X DISTRIBUTION.
|
||||||
|
|
||||||
|
LCC is a C89 ("ANSI C") compiler designed to be highly retargetable.
|
||||||
|
|
||||||
|
LOG describes the changes since the last release.
|
||||||
|
|
||||||
|
CPYRIGHT describes the conditions under you can use, copy, modify, and
|
||||||
|
distribute lcc or works derived from lcc.
|
||||||
|
|
||||||
|
doc/install.html is an HTML file that gives a complete description of
|
||||||
|
the distribution and installation instructions.
|
||||||
|
|
||||||
|
Chris Fraser / cwf@aya.yale.edu
|
||||||
|
David Hanson / drh@drhanson.net
|
||||||
|
*/
|
||||||
|
#include "../frontend.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char* name;
|
||||||
|
enum CSTD_KEYWORD std_type;
|
||||||
|
enum TokenType tok;
|
||||||
|
} keywords[] = {
|
||||||
|
#define X(name, std_type, tok, ...) { #name, std_type, tok },
|
||||||
|
KEYWORD_TABLE
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
|
||||||
|
// by using binary search to find the keyword
|
||||||
|
static inline int keyword_cmp(const char* name, int len) {
|
||||||
|
int low = 0;
|
||||||
|
int high = sizeof(keywords) / sizeof(keywords[0]) - 1;
|
||||||
|
while (low <= high) {
|
||||||
|
int mid = (low + high) / 2;
|
||||||
|
const char *key = keywords[mid].name;
|
||||||
|
int cmp = 0;
|
||||||
|
|
||||||
|
// 自定义字符串比较逻辑
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (name[i] != key[i]) {
|
||||||
|
cmp = (unsigned char)name[i] - (unsigned char)key[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (name[i] == '\0') break; // 遇到终止符提前结束
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp == 0) {
|
||||||
|
// 完全匹配检查(长度相同)
|
||||||
|
if (key[len] == '\0') return mid;
|
||||||
|
cmp = -1; // 当前关键词比输入长
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp < 0) {
|
||||||
|
high = mid - 1;
|
||||||
|
} else {
|
||||||
|
low = mid + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1; // Not a keyword.
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_lexer(struct Lexer* lexer, const char* file_name, void* stream, lexer_sread_fn sread)
|
||||||
|
{
|
||||||
|
lexer->cur_ptr = lexer->end_ptr = (unsigned char*)&(lexer->buffer);
|
||||||
|
lexer->index = 1;
|
||||||
|
lexer->line = 1;
|
||||||
|
|
||||||
|
lexer->stream = stream;
|
||||||
|
lexer->sread = sread;
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(lexer->buffer) / sizeof(lexer->buffer[0]); i++) {
|
||||||
|
lexer->buffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_buffer(struct Lexer* lexer) {
|
||||||
|
int num = lexer->end_ptr - lexer->cur_ptr;
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
lexer->buffer[i] = lexer->cur_ptr[i];
|
||||||
|
}
|
||||||
|
lexer->cur_ptr = lexer->buffer;
|
||||||
|
|
||||||
|
int read_size = LEXER_BUFFER_SIZE - num;
|
||||||
|
// TODO size_t to int maybe lose precision
|
||||||
|
int got_size = lexer->sread(lexer->buffer + num, read_size, 1, read_size, lexer->stream);
|
||||||
|
if (got_size < 0) {
|
||||||
|
error("lexer read error");
|
||||||
|
} else if (got_size < read_size) {
|
||||||
|
lexer->end_ptr += got_size;
|
||||||
|
lexer->end_ptr[0] = '\0'; // EOF
|
||||||
|
lexer->end_ptr++;
|
||||||
|
} else if (got_size == read_size) {
|
||||||
|
lexer->end_ptr += got_size;
|
||||||
|
} else {
|
||||||
|
error("lexer read error imposible got_size > read_size maybe overflow?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void goto_newline(struct Lexer* lexer) {
|
||||||
|
do {
|
||||||
|
if (lexer->cur_ptr == lexer->end_ptr) {
|
||||||
|
flush_buffer(lexer);
|
||||||
|
lexer->cur_ptr--;
|
||||||
|
}
|
||||||
|
lexer->cur_ptr++;
|
||||||
|
} while (*lexer->cur_ptr != '\n' && *lexer->cur_ptr != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void goto_block_comment(struct Lexer* lexer) {
|
||||||
|
while (1) {
|
||||||
|
if (lexer->end_ptr - lexer->cur_ptr < 2) {
|
||||||
|
flush_buffer(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*lexer->cur_ptr == '\0') {
|
||||||
|
break;
|
||||||
|
} else if (lexer->cur_ptr[0] == '*' && lexer->cur_ptr[1] == '/') {
|
||||||
|
lexer->cur_ptr += 2;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
lexer->cur_ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO escape character not enough
|
||||||
|
static char got_slash(unsigned char* peek) {
|
||||||
|
switch (*peek) {
|
||||||
|
case '\\': return '\\';
|
||||||
|
case '\'': return '\'';
|
||||||
|
case '\"': return '\"';
|
||||||
|
case '\?': return '\?';
|
||||||
|
case '0': return '\0';
|
||||||
|
|
||||||
|
case 'b': return '\b';
|
||||||
|
case 'f': return '\f';
|
||||||
|
case 'n': return '\n';
|
||||||
|
case 'r': return '\r';
|
||||||
|
case 't': return '\t';
|
||||||
|
case 'v': return '\v';
|
||||||
|
default: error("Unknown escape character");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_char_literal(struct Lexer* lexer, struct Token* token) {
|
||||||
|
char val = 0;
|
||||||
|
unsigned char* peek = lexer->cur_ptr + 1;
|
||||||
|
if (*peek == '\\') {
|
||||||
|
peek++;
|
||||||
|
val = got_slash(peek);
|
||||||
|
} else {
|
||||||
|
val = *peek;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*peek != '\'') error("Unclosed character literal");
|
||||||
|
token->constant.ch = val;
|
||||||
|
lexer->cur_ptr = peek + 1;
|
||||||
|
token->constant.have = 1;
|
||||||
|
token->type = TOKEN_CHAR_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_string_literal(struct Lexer* lexer, struct Token* token) {
|
||||||
|
unsigned char* peek = lexer->cur_ptr + 1;
|
||||||
|
// TODO string literal size check
|
||||||
|
char* dest = token->constant.str = xmalloc(LEXER_MAX_TOKEN_SIZE + 1);
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
while (*peek != '"') {
|
||||||
|
if (peek >= lexer->end_ptr) flush_buffer(lexer);
|
||||||
|
|
||||||
|
if (*peek == '\\') { // 处理转义
|
||||||
|
peek++;
|
||||||
|
*peek = got_slash(peek);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= LEXER_MAX_TOKEN_SIZE) error("String too long");
|
||||||
|
dest[len++] = *peek++;
|
||||||
|
}
|
||||||
|
dest[len] = '\0';
|
||||||
|
lexer->cur_ptr = peek + 1;
|
||||||
|
token->constant.have = 1;
|
||||||
|
token->type = TOKEN_STRING_LITERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME it write by AI maybe error
|
||||||
|
static void parse_number(struct Lexer* lexer, struct Token* token) {
|
||||||
|
unsigned char* peek = lexer->cur_ptr;
|
||||||
|
int base = 10;
|
||||||
|
int is_float = 0;
|
||||||
|
long long int_val = 0;
|
||||||
|
double float_val = 0.0;
|
||||||
|
double fraction = 1.0;
|
||||||
|
|
||||||
|
// 判断进制
|
||||||
|
if (*peek == '0') {
|
||||||
|
peek++;
|
||||||
|
switch (*peek) {
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
base = 16;
|
||||||
|
default:
|
||||||
|
base = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析整数部分
|
||||||
|
while (1) {
|
||||||
|
int digit = -1;
|
||||||
|
if (*peek >= '0' && *peek <= '9') {
|
||||||
|
digit = *peek - '0';
|
||||||
|
} else if (base == 16) {
|
||||||
|
if (*peek >= 'a' && *peek <= 'f') digit = *peek - 'a' + 10;
|
||||||
|
else if (*peek >= 'A' && *peek <= 'F') digit = *peek - 'A' + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digit < 0 || digit >= base) break;
|
||||||
|
|
||||||
|
if (!is_float) {
|
||||||
|
int_val = int_val * base + digit;
|
||||||
|
} else {
|
||||||
|
float_val = float_val * base + digit;
|
||||||
|
fraction *= base;
|
||||||
|
}
|
||||||
|
peek++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析浮点数
|
||||||
|
if (*peek == '.' && base == 10) {
|
||||||
|
is_float = 1;
|
||||||
|
float_val = int_val;
|
||||||
|
peek++;
|
||||||
|
|
||||||
|
while (*peek >= '0' && *peek <= '9') {
|
||||||
|
float_val = float_val * 10.0 + (*peek - '0');
|
||||||
|
fraction *= 10.0;
|
||||||
|
peek++;
|
||||||
|
}
|
||||||
|
float_val /= fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析科学计数法
|
||||||
|
if ((*peek == 'e' || *peek == 'E') && base == 10) {
|
||||||
|
is_float = 1;
|
||||||
|
peek++;
|
||||||
|
int exp_sign = 1;
|
||||||
|
int exponent = 0;
|
||||||
|
|
||||||
|
if (*peek == '+') peek++;
|
||||||
|
else if (*peek == '-') {
|
||||||
|
exp_sign = -1;
|
||||||
|
peek++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*peek >= '0' && *peek <= '9') {
|
||||||
|
exponent = exponent * 10 + (*peek - '0');
|
||||||
|
peek++;
|
||||||
|
}
|
||||||
|
// float_val *= pow(10.0, exp_sign * exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储结果
|
||||||
|
lexer->cur_ptr = peek;
|
||||||
|
token->constant.have = 1;
|
||||||
|
if (is_float) {
|
||||||
|
token->constant.d = float_val;
|
||||||
|
token->type = TOKEN_FLOAT_LITERAL;
|
||||||
|
} else {
|
||||||
|
token->constant.ll = int_val;
|
||||||
|
token->type = TOKEN_INT_LITERAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GOT_ONE_TOKEN_BUF_SIZE 64
|
||||||
|
// /zh/c/language/operator_arithmetic.html
|
||||||
|
void get_token(struct Lexer* lexer, struct Token* token) {
|
||||||
|
// 需要保证缓冲区始终可读
|
||||||
|
if (lexer->end_ptr - lexer->cur_ptr < GOT_ONE_TOKEN_BUF_SIZE) {
|
||||||
|
flush_buffer(lexer);
|
||||||
|
}
|
||||||
|
register unsigned char* peek = lexer->cur_ptr;
|
||||||
|
|
||||||
|
// 快速跳过空白符
|
||||||
|
while (*peek == ' ' || *peek == '\t') {
|
||||||
|
if (peek == lexer->end_ptr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
peek++;
|
||||||
|
}
|
||||||
|
if (peek != lexer->cur_ptr) {
|
||||||
|
// To TOKEN_FLUSH
|
||||||
|
lexer->cur_ptr = peek;
|
||||||
|
token->type = TOKEN_FLUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TokenType tok = TOKEN_INIT;
|
||||||
|
struct TokenConstant constant;
|
||||||
|
constant.have = 0;
|
||||||
|
|
||||||
|
// once step
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_EQ; break;
|
||||||
|
default: peek--, tok = TOKEN_ASSIGN; break;
|
||||||
|
} break;
|
||||||
|
case '+':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '+': tok = TOKEN_ADD_ADD; break;
|
||||||
|
case '=': tok = TOKEN_ASSIGN_ADD; break;
|
||||||
|
default: peek--, tok = TOKEN_ADD; break;
|
||||||
|
} break;
|
||||||
|
case '-':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '-': tok = TOKEN_SUB_SUB; break;
|
||||||
|
case '=': tok = TOKEN_ASSIGN_SUB; break;
|
||||||
|
|
||||||
|
case '>': tok = TOKEN_DEREF; break;
|
||||||
|
default: peek--, tok = TOKEN_SUB; break;
|
||||||
|
} break;
|
||||||
|
case '*':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_ASSIGN_MUL; break;
|
||||||
|
default: peek--, tok = TOKEN_MUL; break;
|
||||||
|
} break;
|
||||||
|
case '/':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_ASSIGN_DIV; break;
|
||||||
|
case '/': {
|
||||||
|
// need get a new line to parse
|
||||||
|
goto_newline(lexer);
|
||||||
|
tok = TOKEN_LINE_COMMENT;
|
||||||
|
goto END;
|
||||||
|
}
|
||||||
|
case '*': {
|
||||||
|
lexer->cur_ptr = peek;
|
||||||
|
goto_block_comment(lexer);
|
||||||
|
tok = TOKEN_BLOCK_COMMENT;
|
||||||
|
goto END;
|
||||||
|
}
|
||||||
|
default: peek--, tok = TOKEN_DIV; break;
|
||||||
|
} break;
|
||||||
|
case '%':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_ASSIGN_MOD; break;
|
||||||
|
default: peek--, tok = TOKEN_MOD; break;
|
||||||
|
} break;
|
||||||
|
case '&':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '&': tok = TOKEN_AND_AND; break;
|
||||||
|
case '=': tok = TOKEN_ASSIGN_AND; break;
|
||||||
|
default: peek--, tok = TOKEN_AND; break;
|
||||||
|
} break;
|
||||||
|
case '|':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '|': tok = TOKEN_OR_OR; break;
|
||||||
|
case '=': tok = TOKEN_ASSIGN_OR; break;
|
||||||
|
default: peek--, tok = TOKEN_OR; break;
|
||||||
|
} break;
|
||||||
|
case '^':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_ASSIGN_XOR; break;
|
||||||
|
default: peek--, tok = TOKEN_XOR; break;
|
||||||
|
} break;
|
||||||
|
case '<':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_LE; break;
|
||||||
|
case '<': tok = (*peek == '=') ? (peek++, TOKEN_ASSIGN_L_SH) : TOKEN_L_SH; break;
|
||||||
|
default: peek--, tok = TOKEN_LT; break;
|
||||||
|
} break;
|
||||||
|
case '>':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_GE; break;
|
||||||
|
case '>': tok = (*peek == '=') ? (peek++, TOKEN_ASSIGN_R_SH) : TOKEN_R_SH; break;
|
||||||
|
default: peek--, tok = TOKEN_GT; break;
|
||||||
|
} break;
|
||||||
|
case '~':
|
||||||
|
tok = TOKEN_BIT_NOT; break;
|
||||||
|
case '!':
|
||||||
|
switch (*peek++) {
|
||||||
|
case '=': tok = TOKEN_NEQ; break;
|
||||||
|
default: peek--, tok = TOKEN_NOT; break;
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
tok = TOKEN_L_BRACKET; break;
|
||||||
|
case ']':
|
||||||
|
tok = TOKEN_R_BRACKET; break;
|
||||||
|
case '(':
|
||||||
|
tok = TOKEN_L_PAREN; break;
|
||||||
|
case ')':
|
||||||
|
tok = TOKEN_R_PAREN; break;
|
||||||
|
case '{':
|
||||||
|
tok = TOKEN_L_BRACE; break;
|
||||||
|
case '}':
|
||||||
|
tok = TOKEN_R_BRACE; break;
|
||||||
|
case ';':
|
||||||
|
tok = TOKEN_SEMICOLON; break;
|
||||||
|
case ',':
|
||||||
|
tok = TOKEN_COMMA; break;
|
||||||
|
case ':':
|
||||||
|
tok = TOKEN_COLON; break;
|
||||||
|
case '.':
|
||||||
|
if (peek[0] == '.' && peek[1] == '.') {
|
||||||
|
peek += 2;
|
||||||
|
tok = TOKEN_ELLIPSIS;
|
||||||
|
} else {
|
||||||
|
tok = TOKEN_DOT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
tok = TOKEN_COND; break;
|
||||||
|
case '\v': case '\r': case '\f': // FIXME it parse as a blank character
|
||||||
|
tok = TOKEN_FLUSH; break;
|
||||||
|
case '\n':
|
||||||
|
// you need to flush a newline or blank
|
||||||
|
lexer->line++;
|
||||||
|
tok = TOKEN_FLUSH; break;
|
||||||
|
case '#':
|
||||||
|
warn("TODO: #define\n");
|
||||||
|
goto_newline(lexer);
|
||||||
|
tok = TOKEN_FLUSH;
|
||||||
|
goto END;
|
||||||
|
case '\0':
|
||||||
|
// EOF
|
||||||
|
tok = TOKEN_EOF;
|
||||||
|
goto END;
|
||||||
|
case '\'':
|
||||||
|
return parse_char_literal(lexer, token);
|
||||||
|
return;
|
||||||
|
case '"':
|
||||||
|
return parse_string_literal(lexer, token);
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
return parse_number(lexer, token);
|
||||||
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||||
|
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
|
||||||
|
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
|
||||||
|
case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
|
||||||
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||||
|
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
|
||||||
|
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
|
||||||
|
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':case 'Y': case 'Z':
|
||||||
|
case '_':
|
||||||
|
// TOKEN_IDENT
|
||||||
|
if (*peek == 'L' && *peek == '\'' || *peek == 'L' && *peek == '"') {
|
||||||
|
error("unsupport wide-character char literal by `L` format");
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
if (peek == lexer->end_ptr) {
|
||||||
|
error("unsupport outof 64 length identifier");
|
||||||
|
}
|
||||||
|
if ((*peek >= 'a' && *peek <= 'z') || (*peek >= 'A' && *peek <= 'Z') ||
|
||||||
|
(*peek == '_') || (*peek >= '0' && *peek <= '9')) {
|
||||||
|
peek++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = keyword_cmp(lexer->cur_ptr, peek - (lexer->cur_ptr));
|
||||||
|
if (res == -1) {
|
||||||
|
int strlen = peek - lexer->cur_ptr;
|
||||||
|
unsigned char* str = xmalloc(strlen + 1);
|
||||||
|
constant.have = 1;
|
||||||
|
constant.str = str;
|
||||||
|
for (int i = 0; i < strlen; i++) {
|
||||||
|
str[i] = lexer->cur_ptr[i];
|
||||||
|
}
|
||||||
|
str[strlen] = '\0';
|
||||||
|
constant.have = 1;
|
||||||
|
constant.str = str;
|
||||||
|
tok = TOKEN_IDENT; break;
|
||||||
|
} else {
|
||||||
|
tok = keywords[res].tok; break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
error("unsupport char in sourse code `%c`", *(lexer->cur_ptr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer->cur_ptr = peek;
|
||||||
|
END:
|
||||||
|
token->constant = constant;
|
||||||
|
token->type = tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_token maybe got invalid (with parser)
|
||||||
|
void get_valid_token(struct Lexer* lexer, struct Token* token) {
|
||||||
|
enum TokenType type;
|
||||||
|
do {
|
||||||
|
get_token(lexer, token);
|
||||||
|
type = token->type;
|
||||||
|
} while (type == TOKEN_FLUSH || type == TOKEN_LINE_COMMENT || type == TOKEN_BLOCK_COMMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成字符串映射(根据需求选择#str或#name)
|
||||||
|
static const char* token_strings[] = {
|
||||||
|
// 普通token使用#str
|
||||||
|
#define X(str, tok) [tok] = #str,
|
||||||
|
TOKEN_TABLE
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
// 关键字使用#name
|
||||||
|
#define X(name, std, tok) [tok] = #name,
|
||||||
|
KEYWORD_TABLE
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* get_token_name(enum TokenType type) {
|
||||||
|
return token_strings[type];
|
||||||
|
}
|
40
ccompiler/frontend/lexer/lexer.h
Normal file
40
ccompiler/frontend/lexer/lexer.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef __LEXER_H__
|
||||||
|
#define __LEXER_H__
|
||||||
|
|
||||||
|
#include "token.h"
|
||||||
|
#define LEXER_MAX_TOKEN_SIZE 63
|
||||||
|
#define LEXER_BUFFER_SIZE 4095
|
||||||
|
|
||||||
|
typedef int (*lexer_sread_fn)(void *dst_buf, int dst_size,
|
||||||
|
int elem_size, int count, void *stream);
|
||||||
|
|
||||||
|
struct Lexer {
|
||||||
|
int line;
|
||||||
|
int index;
|
||||||
|
// const char current_file_name[LEXER_BUFFER_SIZE+1];
|
||||||
|
|
||||||
|
unsigned char* cur_ptr; // 当前扫描的字符,但是还没有开始扫描
|
||||||
|
unsigned char* end_ptr; // 缓冲区最后一个字符的下一个位置
|
||||||
|
char buffer[LEXER_BUFFER_SIZE+1];
|
||||||
|
|
||||||
|
lexer_sread_fn sread;
|
||||||
|
void* stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
enum TokenType type;
|
||||||
|
struct TokenConstant constant;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_lexer(struct Lexer* lexer, const char* file_name, void* stream,
|
||||||
|
lexer_sread_fn sread);
|
||||||
|
|
||||||
|
//
|
||||||
|
void get_token(struct Lexer* lexer, struct Token* token);
|
||||||
|
|
||||||
|
// get_token maybe got invalid (with parser as TOKEN_FLUSH)
|
||||||
|
void get_valid_token(struct Lexer* lexer, struct Token* token);
|
||||||
|
|
||||||
|
const char* get_token_name(enum TokenType token);
|
||||||
|
|
||||||
|
#endif
|
46
ccompiler/frontend/lexer/tests/test_lexer.c
Normal file
46
ccompiler/frontend/lexer/tests/test_lexer.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "../lexer.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
// gcc -g ../lexer.c test_lexer.c -o test_lexer
|
||||||
|
/*
|
||||||
|
struct TokenConstant {
|
||||||
|
int have;
|
||||||
|
union {
|
||||||
|
char ch;
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
long long ll;
|
||||||
|
char* str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
int g_num;
|
||||||
|
int g_num_arr[3];
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
const char* file_name = "test_lexer.c";
|
||||||
|
if (argc == 2) {
|
||||||
|
file_name = argv[1];
|
||||||
|
}
|
||||||
|
FILE* fp = fopen(file_name, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
perror("open file failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("open file success\n");
|
||||||
|
|
||||||
|
struct Lexer lexer;
|
||||||
|
init_lexer(&lexer, "test_lexter.c", fp, (lexer_sread_fn)fread_s);
|
||||||
|
struct Token tok;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
get_valid_token(&lexer, &tok);
|
||||||
|
if (tok.type == TOKEN_EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("line: %d, column: %d, type: %3d, typename: %s\n",
|
||||||
|
lexer.line, lexer.index, tok.type, get_token_name(tok.type));
|
||||||
|
}
|
||||||
|
}
|
250
ccompiler/frontend/lexer/token.h
Normal file
250
ccompiler/frontend/lexer/token.h
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
#ifndef __TOKEN_H__
|
||||||
|
#define __TOKEN_H__
|
||||||
|
|
||||||
|
enum CSTD_KEYWORD {
|
||||||
|
CSTD_C89,
|
||||||
|
CSTD_C99,
|
||||||
|
CEXT_ASM,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using Binary Search To Fast Find Keyword
|
||||||
|
#define KEYWORD_TABLE \
|
||||||
|
X(asm , CEXT_ASM, TOKEN_ASM) \
|
||||||
|
X(break , CSTD_C89, TOKEN_BREAK) \
|
||||||
|
X(case , CSTD_C89, TOKEN_CASE) \
|
||||||
|
X(char , CSTD_C89, TOKEN_CHAR) \
|
||||||
|
X(const , CSTD_C89, TOKEN_CONST) \
|
||||||
|
X(continue , CSTD_C89, TOKEN_CONTINUE) \
|
||||||
|
X(default , CSTD_C89, TOKEN_DEFAULT) \
|
||||||
|
X(do , CSTD_C89, TOKEN_DO) \
|
||||||
|
X(double , CSTD_C89, TOKEN_DOUBLE) \
|
||||||
|
X(else , CSTD_C89, TOKEN_ELSE) \
|
||||||
|
X(enum , CSTD_C89, TOKEN_ENUM) \
|
||||||
|
X(extern , CSTD_C89, TOKEN_EXTERN) \
|
||||||
|
X(float , CSTD_C89, TOKEN_FLOAT) \
|
||||||
|
X(for , CSTD_C89, TOKEN_FOR) \
|
||||||
|
X(goto , CSTD_C89, TOKEN_GOTO) \
|
||||||
|
X(if , CSTD_C89, TOKEN_IF) \
|
||||||
|
X(inline , CSTD_C99, TOKEN_INLINE) \
|
||||||
|
X(int , CSTD_C89, TOKEN_INT) \
|
||||||
|
X(long , CSTD_C89, TOKEN_LONG) \
|
||||||
|
X(register , CSTD_C89, TOKEN_REGISTER) \
|
||||||
|
X(restrict , CSTD_C99, TOKEN_RESTRICT) \
|
||||||
|
X(return , CSTD_C89, TOKEN_RETURN) \
|
||||||
|
X(short , CSTD_C89, TOKEN_SHORT) \
|
||||||
|
X(signed , CSTD_C89, TOKEN_SIGNED) \
|
||||||
|
X(sizeof , CSTD_C89, TOKEN_SIZEOF) \
|
||||||
|
X(static , CSTD_C89, TOKEN_STATIC) \
|
||||||
|
X(struct , CSTD_C89, TOKEN_STRUCT) \
|
||||||
|
X(switch , CSTD_C89, TOKEN_SWITCH) \
|
||||||
|
X(typedef , CSTD_C89, TOKEN_TYPEDEF) \
|
||||||
|
X(union , CSTD_C89, TOKEN_UNION) \
|
||||||
|
X(unsigned , CSTD_C89, TOKEN_UNSIGNED) \
|
||||||
|
X(void , CSTD_C89, TOKEN_VOID) \
|
||||||
|
X(volatile , CSTD_C89, TOKEN_VOLATILE) \
|
||||||
|
X(while , CSTD_C89, TOKEN_WHILE) \
|
||||||
|
// KEYWORD_TABLE
|
||||||
|
|
||||||
|
#define TOKEN_TABLE \
|
||||||
|
X(EOF , TOKEN_EOF) \
|
||||||
|
X(init , TOKEN_INIT) \
|
||||||
|
X(flush , TOKEN_FLUSH) \
|
||||||
|
X("==" , TOKEN_EQ) \
|
||||||
|
X("=" , TOKEN_ASSIGN) \
|
||||||
|
X("++" , TOKEN_ADD_ADD) \
|
||||||
|
X("+=" , TOKEN_ASSIGN_ADD) \
|
||||||
|
X("+" , TOKEN_ADD) \
|
||||||
|
X("--" , TOKEN_SUB_SUB) \
|
||||||
|
X("-=" , TOKEN_ASSIGN_SUB) \
|
||||||
|
X("->" , TOKEN_DEREF) \
|
||||||
|
X("-" , TOKEN_SUB) \
|
||||||
|
X("*=" , TOKEN_ASSIGN_MUL) \
|
||||||
|
X("*" , TOKEN_MUL) \
|
||||||
|
X("/=" , TOKEN_ASSIGN_DIV) \
|
||||||
|
X("/" , TOKEN_DIV) \
|
||||||
|
X("//" , TOKEN_LINE_COMMENT) \
|
||||||
|
X("/* */" , TOKEN_BLOCK_COMMENT) \
|
||||||
|
X("%=" , TOKEN_ASSIGN_MOD) \
|
||||||
|
X("%" , TOKEN_MOD) \
|
||||||
|
X("&&" , TOKEN_AND_AND) \
|
||||||
|
X("&=" , TOKEN_ASSIGN_AND) \
|
||||||
|
X("&" , TOKEN_AND) \
|
||||||
|
X("||" , TOKEN_OR_OR) \
|
||||||
|
X("|=" , TOKEN_ASSIGN_OR) \
|
||||||
|
X("|" , TOKEN_OR) \
|
||||||
|
X("^=" , TOKEN_ASSIGN_XOR) \
|
||||||
|
X("^" , TOKEN_XOR) \
|
||||||
|
X("<<=" , TOKEN_ASSIGN_L_SH) \
|
||||||
|
X("<<" , TOKEN_L_SH) \
|
||||||
|
X("<=" , TOKEN_LE) \
|
||||||
|
X("<" , TOKEN_LT) \
|
||||||
|
X(">>=" , TOKEN_ASSIGN_R_SH) \
|
||||||
|
X(">>" , TOKEN_R_SH) \
|
||||||
|
X(">=" , TOKEN_GE) \
|
||||||
|
X(">" , TOKEN_GT) \
|
||||||
|
X("!" , TOKEN_NOT) \
|
||||||
|
X("!=" , TOKEN_NEQ) \
|
||||||
|
X("~" , TOKEN_BIT_NOT) \
|
||||||
|
X("[" , TOKEN_L_BRACKET) \
|
||||||
|
X("]" , TOKEN_R_BRACKET) \
|
||||||
|
X("(" , TOKEN_L_PAREN) \
|
||||||
|
X(")" , TOKEN_R_PAREN) \
|
||||||
|
X("{" , TOKEN_L_BRACE) \
|
||||||
|
X("}" , TOKEN_R_BRACE) \
|
||||||
|
X(";" , TOKEN_SEMICOLON) \
|
||||||
|
X("," , TOKEN_COMMA) \
|
||||||
|
X(":" , TOKEN_COLON) \
|
||||||
|
X("." , TOKEN_DOT) \
|
||||||
|
X("..." , TOKEN_ELLIPSIS) \
|
||||||
|
X("?" , TOKEN_COND) \
|
||||||
|
X(identifier , TOKEN_IDENT) \
|
||||||
|
X(int_literal , TOKEN_INT_LITERAL) \
|
||||||
|
X(float_literal , TOKEN_FLOAT_LITERAL) \
|
||||||
|
X(char_literal , TOKEN_CHAR_LITERAL) \
|
||||||
|
X(string_literal , TOKEN_STRING_LITERAL) \
|
||||||
|
// END
|
||||||
|
|
||||||
|
// 定义TokenType枚举
|
||||||
|
enum TokenType {
|
||||||
|
// 处理普通token
|
||||||
|
#define X(str, tok) tok,
|
||||||
|
TOKEN_TABLE
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
// 处理关键字(保持原有格式)
|
||||||
|
#define X(name, std, tok) tok,
|
||||||
|
KEYWORD_TABLE
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TokenConstant {
|
||||||
|
int have;
|
||||||
|
union {
|
||||||
|
char ch;
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
long long ll;
|
||||||
|
char* str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// "break"
|
||||||
|
// "case"
|
||||||
|
// "char"
|
||||||
|
// "const"
|
||||||
|
// "continue"
|
||||||
|
// "default"
|
||||||
|
// "do"
|
||||||
|
// "double"
|
||||||
|
// "else"
|
||||||
|
// "enum"
|
||||||
|
// "extern"
|
||||||
|
// "float"
|
||||||
|
// "for"
|
||||||
|
// "goto"
|
||||||
|
// "if"
|
||||||
|
// "inline (C99)"
|
||||||
|
// "int"
|
||||||
|
// "long"
|
||||||
|
// "register"
|
||||||
|
// "restrict (C99)"
|
||||||
|
// "return"
|
||||||
|
// "short"
|
||||||
|
// "signed"
|
||||||
|
// "sizeof"
|
||||||
|
// "static"
|
||||||
|
// "struct"
|
||||||
|
// "switch"
|
||||||
|
// "typedef"
|
||||||
|
// "union"
|
||||||
|
// "unsigned"
|
||||||
|
// "void"
|
||||||
|
// "volatile"
|
||||||
|
// "while"
|
||||||
|
|
||||||
|
// alignas (C23)
|
||||||
|
// alignof (C23)
|
||||||
|
// auto
|
||||||
|
// bool (C23)
|
||||||
|
// constexpr (C23)
|
||||||
|
// false (C23)
|
||||||
|
// nullptr (C23)
|
||||||
|
// static_assert (C23)
|
||||||
|
// thread_local (C23)
|
||||||
|
// true (C23)
|
||||||
|
// typeof (C23)
|
||||||
|
// typeof_unqual (C23)
|
||||||
|
// _Alignas (C11)
|
||||||
|
// _Alignof (C11)
|
||||||
|
// _Atomic (C11)
|
||||||
|
// _BitInt (C23)
|
||||||
|
// _Bool (C99)
|
||||||
|
// _Complex (C99)
|
||||||
|
// _Decimal128 (C23)
|
||||||
|
// _Decimal32 (C23)
|
||||||
|
// _Decimal64 (C23)
|
||||||
|
// _Generic (C11)
|
||||||
|
// _Imaginary (C99)
|
||||||
|
// _Noreturn (C11)
|
||||||
|
// _Static_assert (C11)
|
||||||
|
// _Thread_local (C11)
|
||||||
|
|
||||||
|
// a = b
|
||||||
|
// a += b
|
||||||
|
// a -= b
|
||||||
|
// a *= b
|
||||||
|
// a /= b
|
||||||
|
// a %= b
|
||||||
|
// a &= b
|
||||||
|
// a |= b
|
||||||
|
// a ^= b
|
||||||
|
// a <<= b
|
||||||
|
// a >>= b
|
||||||
|
|
||||||
|
// ++a
|
||||||
|
// --a
|
||||||
|
// a++
|
||||||
|
// a--
|
||||||
|
|
||||||
|
// +a
|
||||||
|
// -a
|
||||||
|
// a + b
|
||||||
|
// a - b
|
||||||
|
// a * b
|
||||||
|
// a / b
|
||||||
|
// a % b
|
||||||
|
// ~a
|
||||||
|
// a & b
|
||||||
|
// a | b
|
||||||
|
// a ^ b
|
||||||
|
// a << b
|
||||||
|
// a >> b
|
||||||
|
|
||||||
|
// !a
|
||||||
|
// a && b
|
||||||
|
// a || b
|
||||||
|
|
||||||
|
// a == b
|
||||||
|
// a != b
|
||||||
|
// a < b
|
||||||
|
// a > b
|
||||||
|
// a <= b
|
||||||
|
// a >= b
|
||||||
|
|
||||||
|
// a[b]
|
||||||
|
// *a
|
||||||
|
// &a
|
||||||
|
// a->b
|
||||||
|
// a.b
|
||||||
|
|
||||||
|
// a(...)
|
||||||
|
// a, b
|
||||||
|
// (type) a
|
||||||
|
// a ? b : c
|
||||||
|
// sizeof
|
||||||
|
|
||||||
|
// _Alignof
|
||||||
|
// (C11)
|
||||||
|
|
||||||
|
#endif
|
18
ccompiler/frontend/parser/ast/README.md
Normal file
18
ccompiler/frontend/parser/ast/README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
- ast.c 作为抽象语法树的定义
|
||||||
|
|
||||||
|
- block.c 作为块的实现主要用于处理作用域,需要符号表
|
||||||
|
|
||||||
|
- decl.c 作为声明的实现,其中主要携带变量声明,函数声明见 func.c ,需要符号表
|
||||||
|
|
||||||
|
- func.c 作为函数的实现,其中主要携带函数声明,以及函数定义,需要符号表
|
||||||
|
|
||||||
|
- expr.c 作为表达式的实现。需要符号表
|
||||||
|
|
||||||
|
- stmt.c 作为语句的实现。需要表达式类型判断合法性
|
||||||
|
|
||||||
|
- term.c 作为终结符的实现。需要表达式类型判断合法性
|
||||||
|
|
||||||
|
- program.c 作为词法分析(语义分析)入口函数,可以根据parser结构生成AST
|
||||||
|
|
||||||
|
其中stmt参考cppreference
|
||||||
|
其中expr参考AI以及CParser
|
173
ccompiler/frontend/parser/ast/ast.c
Normal file
173
ccompiler/frontend/parser/ast/ast.c
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include "ast.h"
|
||||||
|
#include "../parser.h"
|
||||||
|
struct ASTNode* new_ast_node(void) {
|
||||||
|
struct ASTNode* node = xmalloc(sizeof(struct ASTNode));
|
||||||
|
init_ast_node(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_ast_node(struct ASTNode* node) {
|
||||||
|
node->type = NT_INIT;
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) {
|
||||||
|
node->children[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* find_ast_node(struct ASTNode* node, enum ASTType type) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
static void pnt_depth(int depth) {
|
||||||
|
for (int i = 0; i < depth; i++) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pnt_ast(struct ASTNode* node, int depth) {
|
||||||
|
if (!node) return;
|
||||||
|
pnt_depth(depth);
|
||||||
|
switch (node->type) {
|
||||||
|
case NT_ROOT:
|
||||||
|
for (int i = 0; i < node->root.child_size; i++) {
|
||||||
|
pnt_ast(node->root.children[i], depth);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case NT_ADD : printf("+ \n"); break; // (expr) + (expr)
|
||||||
|
case NT_SUB : printf("- \n"); break; // (expr) - (expr)
|
||||||
|
case NT_MUL : printf("* \n"); break; // (expr) * (expr)
|
||||||
|
case NT_DIV : printf("/ \n"); break; // (expr) / (expr)
|
||||||
|
case NT_MOD : printf("%%\n"); break; // (expr) % (expr)
|
||||||
|
case NT_AND : printf("& \n"); break; // (expr) & (expr)
|
||||||
|
case NT_OR : printf("| \n"); break; // (expr) | (expr)
|
||||||
|
case NT_XOR : printf("^ \n"); break; // (expr) ^ (expr)
|
||||||
|
case NT_L_SH : printf("<<\n"); break; // (expr) << (expr)
|
||||||
|
case NT_R_SH : printf(">>\n"); break; // (expr) >> (expr)
|
||||||
|
case NT_EQ : printf("==\n"); break; // (expr) == (expr)
|
||||||
|
case NT_NEQ : printf("!=\n"); break; // (expr) != (expr)
|
||||||
|
case NT_LE : printf("<=\n"); break; // (expr) <= (expr)
|
||||||
|
case NT_GE : printf(">=\n"); break; // (expr) >= (expr)
|
||||||
|
case NT_LT : printf("< \n"); break; // (expr) < (expr)
|
||||||
|
case NT_GT : printf("> \n"); break; // (expr) > (expr)
|
||||||
|
case NT_AND_AND : printf("&&\n"); break; // (expr) && (expr)
|
||||||
|
case NT_OR_OR : printf("||\n"); break; // (expr) || (expr)
|
||||||
|
case NT_NOT : printf("! \n"); break; // ! (expr)
|
||||||
|
case NT_BIT_NOT : printf("~ \n"); break; // ~ (expr)
|
||||||
|
case NT_COMMA : printf(", \n"); break; // expr, expr 逗号运算符
|
||||||
|
case NT_ASSIGN : printf("= \n"); break; // (expr) = (expr)
|
||||||
|
// case NT_COND : // (expr) ? (expr) : (expr)
|
||||||
|
|
||||||
|
case NT_STMT_EMPTY : // ;
|
||||||
|
printf(";\n");
|
||||||
|
break;
|
||||||
|
case NT_STMT_IF : // if (cond) { ... } [else {...}]
|
||||||
|
printf("if");
|
||||||
|
pnt_ast(node->if_stmt.cond, depth+1);
|
||||||
|
pnt_ast(node->if_stmt.if_stmt, depth+1);
|
||||||
|
if (node->if_stmt.else_stmt) {
|
||||||
|
pnt_depth(depth);
|
||||||
|
printf("else");
|
||||||
|
pnt_ast(node->if_stmt.else_stmt, depth+1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_STMT_WHILE : // while (cond) { ... }
|
||||||
|
printf("while\n");
|
||||||
|
pnt_ast(node->while_stmt.cond, depth+1);
|
||||||
|
pnt_ast(node->while_stmt.body, depth+1);
|
||||||
|
break;
|
||||||
|
case NT_STMT_DOWHILE : // do {...} while (cond)
|
||||||
|
printf("do-while\n");
|
||||||
|
pnt_ast(node->do_while_stmt.body, depth+1);
|
||||||
|
pnt_ast(node->do_while_stmt.cond, depth+1);
|
||||||
|
break;
|
||||||
|
case NT_STMT_FOR : // for (init; cond; iter) {...}
|
||||||
|
printf("for\n");
|
||||||
|
if (node->for_stmt.init)
|
||||||
|
pnt_ast(node->for_stmt.init, depth+1);
|
||||||
|
if (node->for_stmt.cond)
|
||||||
|
pnt_ast(node->for_stmt.cond, depth+1);
|
||||||
|
if (node->for_stmt.iter)
|
||||||
|
pnt_ast(node->for_stmt.iter, depth+1);
|
||||||
|
pnt_ast(node->for_stmt.body, depth+1);
|
||||||
|
break;
|
||||||
|
case NT_STMT_SWITCH : // switch (expr) { case ... }
|
||||||
|
case NT_STMT_BREAK : // break;
|
||||||
|
case NT_STMT_CONTINUE : // continue;
|
||||||
|
case NT_STMT_GOTO : // goto label;
|
||||||
|
case NT_STMT_CASE : // case const_expr:
|
||||||
|
case NT_STMT_DEFAULT : // default:
|
||||||
|
case NT_STMT_LABEL : // label:
|
||||||
|
break;
|
||||||
|
case NT_STMT_BLOCK : // { ... }
|
||||||
|
printf("{\n");
|
||||||
|
for (int i = 0; i < node->block.child_size; i++) {
|
||||||
|
pnt_ast(node->block.children[i], depth+1);
|
||||||
|
}
|
||||||
|
pnt_depth(depth);
|
||||||
|
printf("}\n");
|
||||||
|
break;
|
||||||
|
case NT_STMT_RETURN : // return expr;
|
||||||
|
printf("return");
|
||||||
|
if (node->return_stmt.expr_stmt) {
|
||||||
|
printf(" ");
|
||||||
|
pnt_ast(node->return_stmt.expr_stmt, depth+1);
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_STMT_EXPR : // expr;
|
||||||
|
printf("stmt\n");
|
||||||
|
pnt_ast(node->expr_stmt.expr_stmt, depth);
|
||||||
|
pnt_depth(depth);
|
||||||
|
printf(";\n");
|
||||||
|
break;
|
||||||
|
case NT_DECL_VAR : // type name; or type name = expr;
|
||||||
|
printf("decl_val\n");
|
||||||
|
break;
|
||||||
|
case NT_DECL_FUNC: // type func_name(param_list);
|
||||||
|
printf("decl func %s\n", node->func.name->syms.tok.constant.str);
|
||||||
|
break;
|
||||||
|
case NT_FUNC : // type func_name(param_list) {...}
|
||||||
|
printf("def func %s\n", node->func.name->syms.tok.constant.str);
|
||||||
|
// pnt_ast(node->child.func.params, depth);
|
||||||
|
pnt_ast(node->func.body, depth);
|
||||||
|
// pnt_ast(node->child.func.ret, depth);
|
||||||
|
break;
|
||||||
|
case NT_PARAM : // 函数形参
|
||||||
|
printf("param\n");
|
||||||
|
case NT_ARG_LIST : // 实参列表(需要与NT_CALL配合)
|
||||||
|
printf("arg_list\n");
|
||||||
|
case NT_TERM_CALL : // func (expr)
|
||||||
|
printf("call\n");
|
||||||
|
break;
|
||||||
|
case NT_TERM_IDENT:
|
||||||
|
printf("%s\n", node->syms.tok.constant.str);
|
||||||
|
break;
|
||||||
|
case NT_TERM_VAL : // Terminal Symbols like constant, identifier, keyword
|
||||||
|
struct Token * tok = &node->syms.tok;
|
||||||
|
switch (tok->type) {
|
||||||
|
case TOKEN_CHAR_LITERAL:
|
||||||
|
printf("%c\n", tok->constant.ch);
|
||||||
|
break;
|
||||||
|
case TOKEN_INT_LITERAL:
|
||||||
|
printf("%d\n", tok->constant.i);
|
||||||
|
break;
|
||||||
|
case TOKEN_STRING_LITERAL:
|
||||||
|
printf("%s\n", tok->constant.str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown term val\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用子节点递归处理
|
||||||
|
if (node->type <= NT_ASSIGN) { // 表达式类统一处理子节点
|
||||||
|
if (node->expr.left) pnt_ast(node->expr.left, depth+1);
|
||||||
|
if (node->expr.right) pnt_ast(node->expr.right, depth + 1);
|
||||||
|
}
|
||||||
|
}
|
191
ccompiler/frontend/parser/ast/ast.h
Normal file
191
ccompiler/frontend/parser/ast/ast.h
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#ifndef __AST_H__
|
||||||
|
#define __AST_H__
|
||||||
|
|
||||||
|
#include "../../frontend.h"
|
||||||
|
#include "../../lexer/lexer.h"
|
||||||
|
#include "../type.h"
|
||||||
|
|
||||||
|
enum ASTType {
|
||||||
|
NT_INIT,
|
||||||
|
NT_ROOT, // global scope in root node
|
||||||
|
NT_ADD, // (expr) + (expr)
|
||||||
|
NT_SUB, // (expr) - (expr)
|
||||||
|
NT_MUL, // (expr) * (expr)
|
||||||
|
NT_DIV, // (expr) / (expr)
|
||||||
|
NT_MOD, // (expr) % (expr)
|
||||||
|
NT_AND, // (expr) & (expr)
|
||||||
|
NT_OR, // (expr) | (expr)
|
||||||
|
NT_XOR, // (expr) ^ (expr)
|
||||||
|
NT_L_SH, // (expr) << (expr)
|
||||||
|
NT_R_SH, // (expr) >> (expr)
|
||||||
|
NT_EQ, // (expr) == (expr)
|
||||||
|
NT_NEQ, // (expr) != (expr)
|
||||||
|
NT_LE, // (expr) <= (expr)
|
||||||
|
NT_GE, // (expr) >= (expr)
|
||||||
|
NT_LT, // (expr) < (expr)
|
||||||
|
NT_GT, // (expr) > (expr)
|
||||||
|
NT_AND_AND, // (expr) && (expr)
|
||||||
|
NT_OR_OR, // (expr) || (expr)
|
||||||
|
NT_NOT, // ! (expr)
|
||||||
|
NT_BIT_NOT, // ~ (expr)
|
||||||
|
NT_COND, // (expr) ? (expr) : (expr)
|
||||||
|
NT_COMMA, // expr, expr 逗号运算符
|
||||||
|
NT_ASSIGN, // (expr) = (expr)
|
||||||
|
|
||||||
|
NT_ADDRESS, // &expr (取地址)
|
||||||
|
NT_DEREF, // *expr (解引用)
|
||||||
|
NT_INDEX, // arr[index] (数组访问)
|
||||||
|
NT_MEMBER, // struct.member
|
||||||
|
NT_PTR_MEMBER,// ptr->member
|
||||||
|
|
||||||
|
NT_CAST, // (type)expr 强制类型转换
|
||||||
|
NT_SIZEOF, // sizeof(type|expr)
|
||||||
|
// NT_ALIGNOF, // _Alignof(type) (C11)
|
||||||
|
|
||||||
|
NT_STMT_EMPTY, // ;
|
||||||
|
NT_STMT_IF, // if (cond) { ... } [else {...}]
|
||||||
|
NT_STMT_WHILE, // while (cond) { ... }
|
||||||
|
NT_STMT_DOWHILE, // do {...} while (cond)
|
||||||
|
NT_STMT_FOR, // for (init; cond; iter) {...}
|
||||||
|
NT_STMT_SWITCH, // switch (expr) { case ... }
|
||||||
|
NT_STMT_BREAK, // break;
|
||||||
|
NT_STMT_CONTINUE, // continue;
|
||||||
|
NT_STMT_GOTO, // goto label;
|
||||||
|
NT_STMT_CASE, // case const_expr:
|
||||||
|
NT_STMT_DEFAULT, // default:
|
||||||
|
NT_STMT_LABEL, // label:
|
||||||
|
NT_STMT_BLOCK, // { ... }
|
||||||
|
NT_STMT_RETURN, // return expr;
|
||||||
|
NT_STMT_EXPR, // expr;
|
||||||
|
|
||||||
|
NT_BLOCK,
|
||||||
|
// NT_TYPE_BASE, // 基础类型节点
|
||||||
|
// NT_TYPE_PTR, // 指针类型
|
||||||
|
// NT_TYPE_ARRAY, // 数组类型
|
||||||
|
// NT_TYPE_FUNC, // 函数类型
|
||||||
|
// NT_TYPE_QUAL, // 限定符节点
|
||||||
|
|
||||||
|
NT_DECL_VAR, // type name; or type name = expr;
|
||||||
|
NT_DECL_FUNC, // type func_name(param_list);
|
||||||
|
NT_FUNC, // type func_name(param_list) {...}
|
||||||
|
NT_PARAM, // 函数形参
|
||||||
|
NT_ARG_LIST, // 实参列表(需要与NT_CALL配合)
|
||||||
|
|
||||||
|
NT_TERM_CALL, // func (expr)
|
||||||
|
NT_TERM_VAL,
|
||||||
|
NT_TERM_IDENT,
|
||||||
|
NT_TERM_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ASTNode {
|
||||||
|
enum ASTType type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
void *children[6];
|
||||||
|
struct {
|
||||||
|
struct ASTNode** children;
|
||||||
|
int child_size;
|
||||||
|
} root;
|
||||||
|
struct {
|
||||||
|
struct ASTNode** children; // array of children
|
||||||
|
int child_size;
|
||||||
|
} block;
|
||||||
|
struct {
|
||||||
|
struct ASTNode* decl_node;
|
||||||
|
struct Token tok;
|
||||||
|
} syms;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *arr;
|
||||||
|
int size;
|
||||||
|
} params;
|
||||||
|
struct {
|
||||||
|
const char* name;
|
||||||
|
struct ASTNode* params;
|
||||||
|
struct ASTNode* func_decl;
|
||||||
|
} call;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *type;
|
||||||
|
struct ASTNode *name;
|
||||||
|
struct ASTNode *expr_stmt; // optional
|
||||||
|
void* data;
|
||||||
|
} decl_val;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *ret;
|
||||||
|
struct ASTNode *name;
|
||||||
|
struct ASTNode *params; // array of params
|
||||||
|
void* data;
|
||||||
|
} func_decl;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *ret;
|
||||||
|
struct ASTNode *name;
|
||||||
|
struct ASTNode *params; // array of params
|
||||||
|
struct ASTNode *body; // optional
|
||||||
|
} func;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *left;
|
||||||
|
struct ASTNode *right;
|
||||||
|
struct ASTNode *optional; // optional
|
||||||
|
} expr;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *cond;
|
||||||
|
struct ASTNode *if_stmt;
|
||||||
|
struct ASTNode *else_stmt; // optional
|
||||||
|
} if_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *cond;
|
||||||
|
struct ASTNode *body;
|
||||||
|
} switch_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *cond;
|
||||||
|
struct ASTNode *body;
|
||||||
|
} while_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *body;
|
||||||
|
struct ASTNode *cond;
|
||||||
|
} do_while_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *init;
|
||||||
|
struct ASTNode *cond; // optional
|
||||||
|
struct ASTNode *iter; // optional
|
||||||
|
struct ASTNode *body;
|
||||||
|
} for_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *expr_stmt; // optional
|
||||||
|
} return_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *label;
|
||||||
|
} goto_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *label;
|
||||||
|
} label_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *block;
|
||||||
|
} block_stmt;
|
||||||
|
struct {
|
||||||
|
struct ASTNode *expr_stmt;
|
||||||
|
} expr_stmt;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ASTNode* new_ast_node(void);
|
||||||
|
void init_ast_node(struct ASTNode* node);
|
||||||
|
void pnt_ast(struct ASTNode* node, int depth);
|
||||||
|
|
||||||
|
struct Parser;
|
||||||
|
typedef struct ASTNode* (*parse_func_t) (struct Parser*);
|
||||||
|
|
||||||
|
void parse_prog(struct Parser* parser);
|
||||||
|
struct ASTNode* parse_block(struct Parser* parser);
|
||||||
|
struct ASTNode* parse_stmt(struct Parser* parser);
|
||||||
|
struct ASTNode* parse_expr(struct Parser* parser);
|
||||||
|
struct ASTNode* parse_func(struct Parser* parser);
|
||||||
|
struct ASTNode* parse_decl(struct Parser* parser);
|
||||||
|
|
||||||
|
struct ASTNode* parse_ident(struct Parser* parser);
|
||||||
|
struct ASTNode* parse_type(struct Parser* parser);
|
||||||
|
|
||||||
|
int peek_decl(struct Parser* parser);
|
||||||
|
|
||||||
|
struct ASTNode* parser_ident_without_pop(struct Parser* parser);
|
||||||
|
|
||||||
|
#endif
|
50
ccompiler/frontend/parser/ast/block.c
Normal file
50
ccompiler/frontend/parser/ast/block.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
#include "../parser.h"
|
||||||
|
#include "ast.h"
|
||||||
|
#include "../symtab/symtab.h"
|
||||||
|
|
||||||
|
#ifndef BLOCK_MAX_NODE
|
||||||
|
#define BLOCK_MAX_NODE (1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ASTNode* parse_block(struct Parser* parser) {
|
||||||
|
symtab_enter_scope(parser->symtab);
|
||||||
|
|
||||||
|
// parse_decl(parser); // decl_var
|
||||||
|
enum TokenType ttype;
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = NT_BLOCK;
|
||||||
|
flushpeektok(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_L_BRACE) {
|
||||||
|
error("block need '{' start");
|
||||||
|
}
|
||||||
|
poptok(parser);
|
||||||
|
|
||||||
|
node->block.children = malloc(sizeof(struct ASTNode*) * BLOCK_MAX_NODE);
|
||||||
|
struct ASTNode* child = NULL;
|
||||||
|
while (1) {
|
||||||
|
if (peek_decl(parser) == 1) {
|
||||||
|
child = parse_decl(parser);
|
||||||
|
goto ADD_CHILD;
|
||||||
|
}
|
||||||
|
|
||||||
|
flushpeektok(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_R_BRACE:
|
||||||
|
poptok(parser);
|
||||||
|
goto END;
|
||||||
|
default:
|
||||||
|
child = parse_stmt(parser);
|
||||||
|
goto ADD_CHILD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
ADD_CHILD:
|
||||||
|
node->block.children[node->block.child_size++] = child;
|
||||||
|
}
|
||||||
|
END:
|
||||||
|
symtab_leave_scope(parser->symtab);
|
||||||
|
return node;
|
||||||
|
}
|
94
ccompiler/frontend/parser/ast/decl.c
Normal file
94
ccompiler/frontend/parser/ast/decl.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "ast.h"
|
||||||
|
#include "../symtab/symtab.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 false
|
||||||
|
* 1 true
|
||||||
|
*/
|
||||||
|
int peek_decl(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
switch (peektoktype(parser)) {
|
||||||
|
case TOKEN_STATIC:
|
||||||
|
case TOKEN_EXTERN:
|
||||||
|
case TOKEN_REGISTER:
|
||||||
|
case TOKEN_TYPEDEF:
|
||||||
|
error("not impliment");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flushpeektok(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (peektoktype(parser)) {
|
||||||
|
case TOKEN_VOID:
|
||||||
|
case TOKEN_CHAR:
|
||||||
|
case TOKEN_SHORT:
|
||||||
|
case TOKEN_INT:
|
||||||
|
case TOKEN_LONG:
|
||||||
|
case TOKEN_FLOAT:
|
||||||
|
case TOKEN_DOUBLE:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
flushpeektok(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* parse_decl_val(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
// parse_type
|
||||||
|
enum TokenType ttype;
|
||||||
|
struct ASTNode* node;
|
||||||
|
|
||||||
|
struct ASTNode* type_node = parse_type(parser);
|
||||||
|
struct ASTNode* name_node = parser_ident_without_pop(parser);
|
||||||
|
|
||||||
|
node = new_ast_node();
|
||||||
|
node->decl_val.type = type_node;
|
||||||
|
node->decl_val.name = name_node;
|
||||||
|
node->type = NT_DECL_VAR;
|
||||||
|
symtab_add_symbol(parser->symtab, name_node->syms.tok.constant.str, node);
|
||||||
|
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype == TOKEN_ASSIGN) {
|
||||||
|
node->decl_val.expr_stmt = parse_stmt(parser);
|
||||||
|
if (node->decl_val.expr_stmt->type != NT_STMT_EXPR) {
|
||||||
|
error("parser_decl_val want stmt_expr");
|
||||||
|
}
|
||||||
|
} else if (ttype == TOKEN_SEMICOLON) {
|
||||||
|
poptok(parser);
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
} else {
|
||||||
|
error("parser_decl_val syntax error");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类型解析入口改进
|
||||||
|
struct ASTNode* parse_decl(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
int idx;
|
||||||
|
enum TokenType ttype;
|
||||||
|
struct ASTNode* node;
|
||||||
|
|
||||||
|
if (peek_decl(parser) == 0) {
|
||||||
|
error("syntax error expect decl_val TYPE");
|
||||||
|
}
|
||||||
|
if (peektoktype(parser) != TOKEN_IDENT) {
|
||||||
|
error("syntax error expect decl_val IDENT");
|
||||||
|
}
|
||||||
|
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_L_PAREN: // (
|
||||||
|
node = parse_func(parser);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN:
|
||||||
|
case TOKEN_SEMICOLON:
|
||||||
|
node = parse_decl_val(parser);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("syntax error expect decl_val ASSIGN or SEMICOLON");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
409
ccompiler/frontend/parser/ast/expr.c
Normal file
409
ccompiler/frontend/parser/ast/expr.c
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "ast.h"
|
||||||
|
#include "../symtab/symtab.h"
|
||||||
|
|
||||||
|
// Copy from `CParse`
|
||||||
|
/**
|
||||||
|
* Operator precedence classes
|
||||||
|
*/
|
||||||
|
enum Precedence {
|
||||||
|
PREC_BOTTOM,
|
||||||
|
PREC_EXPRESSION, /* , left to right */
|
||||||
|
PREC_ASSIGNMENT, /* = += -= *= /= %= <<= >>= &= ^= |= right to left */
|
||||||
|
PREC_CONDITIONAL, /* ?: right to left */
|
||||||
|
PREC_LOGICAL_OR, /* || left to right */
|
||||||
|
PREC_LOGICAL_AND, /* && left to right */
|
||||||
|
PREC_OR, /* | left to right */
|
||||||
|
PREC_XOR, /* ^ left to right */
|
||||||
|
PREC_AND, /* & left to right */
|
||||||
|
PREC_EQUALITY, /* == != left to right */
|
||||||
|
PREC_RELATIONAL, /* < <= > >= left to right */
|
||||||
|
PREC_SHIFT, /* << >> left to right */
|
||||||
|
PREC_ADDITIVE, /* + - left to right */
|
||||||
|
PREC_MULTIPLICATIVE, /* * / % left to right */
|
||||||
|
PREC_CAST, /* (type) right to left */
|
||||||
|
PREC_UNARY, /* ! ~ ++ -- + - * & sizeof right to left */
|
||||||
|
PREC_POSTFIX, /* () [] -> . left to right */
|
||||||
|
PREC_PRIMARY,
|
||||||
|
PREC_TOP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ParseType {
|
||||||
|
INFIX_PARSER,
|
||||||
|
PREFIX_PARSER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ASTNode *parse_subexpression(struct Parser* parser, enum Precedence prec);
|
||||||
|
|
||||||
|
static struct ASTNode* gen_node2(struct ASTNode* left, struct ASTNode* right,
|
||||||
|
enum ASTType type) {
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = type;
|
||||||
|
node->expr.left = left;
|
||||||
|
node->expr.right = right;
|
||||||
|
// switch (type) {
|
||||||
|
// case NT_ADD : printf("+ \n"); break; // (expr) + (expr)
|
||||||
|
// case NT_SUB : printf("- \n"); break; // (expr) - (expr)
|
||||||
|
// case NT_MUL : printf("* \n"); break; // (expr) * (expr)
|
||||||
|
// case NT_DIV : printf("/ \n"); break; // (expr) / (expr)
|
||||||
|
// case NT_MOD : printf("%%\n"); break; // (expr) % (expr)
|
||||||
|
// case NT_AND : printf("& \n"); break; // (expr) & (expr)
|
||||||
|
// case NT_OR : printf("| \n"); break; // (expr) | (expr)
|
||||||
|
// case NT_XOR : printf("^ \n"); break; // (expr) ^ (expr)
|
||||||
|
// case NT_L_SH : printf("<<\n"); break; // (expr) << (expr)
|
||||||
|
// case NT_R_SH : printf(">>\n"); break; // (expr) >> (expr)
|
||||||
|
// case NT_EQ : printf("==\n"); break; // (expr) == (expr)
|
||||||
|
// case NT_NEQ : printf("!=\n"); break; // (expr) != (expr)
|
||||||
|
// case NT_LE : printf("<=\n"); break; // (expr) <= (expr)
|
||||||
|
// case NT_GE : printf(">=\n"); break; // (expr) >= (expr)
|
||||||
|
// case NT_LT : printf("< \n"); break; // (expr) < (expr)
|
||||||
|
// case NT_GT : printf("> \n"); break; // (expr) > (expr)
|
||||||
|
// case NT_AND_AND : printf("&&\n"); break; // (expr) && (expr)
|
||||||
|
// case NT_OR_OR : printf("||\n"); break; // (expr) || (expr)
|
||||||
|
// case NT_NOT : printf("! \n"); break; // ! (expr)
|
||||||
|
// case NT_BIT_NOT : printf("~ \n"); break; // ~ (expr)
|
||||||
|
// case NT_COMMA : printf(", \n"); break; // expr, expr 逗号运算符
|
||||||
|
// case NT_ASSIGN : printf("= \n"); break; // (expr) = (expr)
|
||||||
|
// // case NT_COND : // (expr) ? (expr) : (expr)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ASTNode* parse_comma(struct Parser* parser, struct ASTNode* left) {
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = NT_COMMA;
|
||||||
|
node->expr.left = left;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_EXPRESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ASTNode* parse_assign(struct Parser* parser, struct ASTNode* left) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype = peektoktype(parser);
|
||||||
|
poptok(parser);
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = NT_ASSIGN;
|
||||||
|
// saved left
|
||||||
|
node->expr.left = left;
|
||||||
|
enum Precedence next = PREC_ASSIGNMENT + 1;
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_ASSIGN :
|
||||||
|
left = parse_subexpression(parser, next);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_ADD :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_ADD);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_SUB :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_SUB);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_MUL :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_MUL);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_DIV :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_DIV);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_MOD :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_MOD);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_L_SH :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_L_SH);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_R_SH :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_R_SH);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_AND :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_AND);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_OR :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_OR);
|
||||||
|
break;
|
||||||
|
case TOKEN_ASSIGN_XOR :
|
||||||
|
left = gen_node2(left, parse_subexpression(parser, next), NT_XOR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("unsupported operator");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node->expr.right = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ASTNode* parse_cmp(struct Parser* parser, struct ASTNode* left) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype = peektoktype(parser);
|
||||||
|
poptok(parser);
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
// saved left
|
||||||
|
node->expr.left = left;
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_EQ:
|
||||||
|
node->type = NT_EQ;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_EQUALITY);
|
||||||
|
break;
|
||||||
|
case TOKEN_NEQ:
|
||||||
|
node->type = NT_NEQ;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_EQUALITY);
|
||||||
|
break;
|
||||||
|
case TOKEN_LT:
|
||||||
|
node->type = NT_LT;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_RELATIONAL);
|
||||||
|
break;
|
||||||
|
case TOKEN_GT:
|
||||||
|
node->type = NT_GT;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_RELATIONAL);
|
||||||
|
break;
|
||||||
|
case TOKEN_LE:
|
||||||
|
node->type = NT_LE;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_RELATIONAL);
|
||||||
|
break;
|
||||||
|
case TOKEN_GE:
|
||||||
|
node->type = NT_GE;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_RELATIONAL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("invalid operator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ASTNode* parse_cal(struct Parser* parser, struct ASTNode* left) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype = peektoktype(parser);
|
||||||
|
poptok(parser);
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->expr.left = left;
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_OR_OR:
|
||||||
|
node->type = NT_OR_OR;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_LOGICAL_OR);
|
||||||
|
break;
|
||||||
|
case TOKEN_AND_AND:
|
||||||
|
node->type = NT_AND_AND;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_LOGICAL_AND);
|
||||||
|
break;
|
||||||
|
case TOKEN_OR:
|
||||||
|
node->type = NT_OR;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_OR);
|
||||||
|
break;
|
||||||
|
case TOKEN_XOR:
|
||||||
|
node->type = NT_XOR;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_XOR);
|
||||||
|
break;
|
||||||
|
case TOKEN_AND:
|
||||||
|
node->type = NT_AND;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_AND);
|
||||||
|
break;
|
||||||
|
case TOKEN_L_SH:
|
||||||
|
node->type = NT_L_SH;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_SHIFT);
|
||||||
|
break;
|
||||||
|
case TOKEN_R_SH:
|
||||||
|
node->type = NT_R_SH;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_SHIFT);
|
||||||
|
break;
|
||||||
|
case TOKEN_ADD:
|
||||||
|
node->type = NT_ADD;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_ADDITIVE);
|
||||||
|
break;
|
||||||
|
case TOKEN_SUB:
|
||||||
|
node->type = NT_SUB;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_ADDITIVE);
|
||||||
|
break;
|
||||||
|
case TOKEN_MUL:
|
||||||
|
node->type = NT_MUL;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_MULTIPLICATIVE);
|
||||||
|
break;
|
||||||
|
case TOKEN_DIV:
|
||||||
|
node->type = NT_DIV;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_MULTIPLICATIVE);
|
||||||
|
break;
|
||||||
|
case TOKEN_MOD:
|
||||||
|
node->type = NT_MOD;
|
||||||
|
node->expr.right = parse_subexpression(parser, PREC_MULTIPLICATIVE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 新增函数调用解析
|
||||||
|
static struct ASTNode* parse_call(struct Parser* parser, struct ASTNode* ident) {
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = NT_TERM_CALL;
|
||||||
|
poptok(parser); // 跳过 '('
|
||||||
|
|
||||||
|
enum TokenType ttype;
|
||||||
|
// 解析参数列表
|
||||||
|
while ((ttype = peektoktype(parser)) != TOKEN_R_PAREN) {
|
||||||
|
// add_arg(node, parse_expr(parser));
|
||||||
|
if (ttype == TOKEN_COMMA) poptok(parser);
|
||||||
|
else poptok(parser);
|
||||||
|
}
|
||||||
|
poptok(parser); // 跳过 ')'
|
||||||
|
|
||||||
|
char* name = ident->syms.tok.constant.str;
|
||||||
|
void* sym = symtab_lookup_symbol(parser->symtab, name);
|
||||||
|
if (sym == NULL) {
|
||||||
|
error("function not decl %s", name);
|
||||||
|
}
|
||||||
|
node->call.name = name;
|
||||||
|
node->call.params = NULL;
|
||||||
|
node->call.func_decl = sym;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ASTNode* parse_paren(struct Parser* parser, struct ASTNode* left) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype;
|
||||||
|
expecttok(parser, TOKEN_L_PAREN);
|
||||||
|
left = parse_subexpression(parser, PREC_EXPRESSION);
|
||||||
|
flushpeektok(parser);
|
||||||
|
expecttok(parser, TOKEN_R_PAREN);
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct ASTNode* (*parse_expr_fun_t)(struct Parser*, struct ASTNode*);
|
||||||
|
static struct expr_prec_table_t {
|
||||||
|
parse_expr_fun_t parser;
|
||||||
|
enum Precedence prec;
|
||||||
|
enum ParseType ptype;
|
||||||
|
} expr_table [256] = {
|
||||||
|
[TOKEN_COMMA] = {parse_comma, PREC_EXPRESSION, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_ADD] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_SUB] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_MUL] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_DIV] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_MOD] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_L_SH] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_R_SH] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_AND] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_OR] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
[TOKEN_ASSIGN_XOR] = {parse_assign, PREC_ASSIGNMENT, INFIX_PARSER},
|
||||||
|
|
||||||
|
[TOKEN_OR_OR] = {parse_cal, PREC_LOGICAL_OR , INFIX_PARSER},
|
||||||
|
[TOKEN_AND_AND] = {parse_cal, PREC_LOGICAL_AND, INFIX_PARSER},
|
||||||
|
[TOKEN_OR] = {parse_cal, PREC_OR , INFIX_PARSER},
|
||||||
|
[TOKEN_XOR] = {parse_cal, PREC_XOR , INFIX_PARSER},
|
||||||
|
[TOKEN_AND] = {parse_cal, PREC_AND , INFIX_PARSER},
|
||||||
|
|
||||||
|
[TOKEN_EQ] = {parse_cmp, PREC_EQUALITY, INFIX_PARSER},
|
||||||
|
[TOKEN_NEQ] = {parse_cmp, PREC_EQUALITY, INFIX_PARSER},
|
||||||
|
[TOKEN_LT] = {parse_cmp, PREC_RELATIONAL, INFIX_PARSER},
|
||||||
|
[TOKEN_LE] = {parse_cmp, PREC_RELATIONAL, INFIX_PARSER},
|
||||||
|
[TOKEN_GT] = {parse_cmp, PREC_RELATIONAL, INFIX_PARSER},
|
||||||
|
[TOKEN_GE] = {parse_cmp, PREC_RELATIONAL, INFIX_PARSER},
|
||||||
|
|
||||||
|
[TOKEN_L_SH] = {parse_cal, PREC_SHIFT , INFIX_PARSER},
|
||||||
|
[TOKEN_R_SH] = {parse_cal, PREC_SHIFT , INFIX_PARSER},
|
||||||
|
[TOKEN_ADD] = {parse_cal, PREC_ADDITIVE , INFIX_PARSER},
|
||||||
|
[TOKEN_SUB] = {parse_cal, PREC_ADDITIVE , INFIX_PARSER},
|
||||||
|
[TOKEN_MUL] = {parse_cal, PREC_MULTIPLICATIVE , INFIX_PARSER},
|
||||||
|
[TOKEN_DIV] = {parse_cal, PREC_MULTIPLICATIVE , INFIX_PARSER},
|
||||||
|
[TOKEN_MOD] = {parse_cal, PREC_MULTIPLICATIVE , INFIX_PARSER},
|
||||||
|
|
||||||
|
[TOKEN_NOT] = {NULL, PREC_UNARY, PREFIX_PARSER},
|
||||||
|
[TOKEN_BIT_NOT] = {NULL, PREC_UNARY, PREFIX_PARSER},
|
||||||
|
[TOKEN_ADD_ADD] = {NULL, PREC_UNARY, PREFIX_PARSER},
|
||||||
|
[TOKEN_SUB_SUB] = {NULL, PREC_UNARY, PREFIX_PARSER},
|
||||||
|
// + - * & sizeof
|
||||||
|
|
||||||
|
[TOKEN_L_PAREN] = {parse_paren, PREC_POSTFIX, INFIX_PARSER},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ASTNode *parse_primary_expression(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
|
||||||
|
struct Token* tok = peektok(parser);
|
||||||
|
struct ASTNode *node = new_ast_node();
|
||||||
|
node->type = NT_TERM_VAL;
|
||||||
|
node->syms.tok = *tok;
|
||||||
|
|
||||||
|
switch (tok->type) {
|
||||||
|
case TOKEN_INT_LITERAL:
|
||||||
|
// node->data.data_type = TYPE_INT;
|
||||||
|
break;
|
||||||
|
case TOKEN_FLOAT_LITERAL:
|
||||||
|
warn("float not supported");
|
||||||
|
break;
|
||||||
|
case TOKEN_CHAR_LITERAL:
|
||||||
|
// node->data.data_type = TYPE_CHAR;
|
||||||
|
break;
|
||||||
|
case TOKEN_STRING_LITERAL:
|
||||||
|
// node->data.data_type = TYPE_POINTER;
|
||||||
|
case TOKEN_IDENT:
|
||||||
|
node = parse_ident(parser);
|
||||||
|
if (peektoktype(parser) == TOKEN_L_PAREN) {
|
||||||
|
node = parse_call(parser, node);
|
||||||
|
} else {
|
||||||
|
void *sym = symtab_lookup_symbol(parser->symtab, tok->constant.str);
|
||||||
|
if (sym == NULL) {
|
||||||
|
error("undefined symbol but use %s", tok->constant.str);
|
||||||
|
}
|
||||||
|
node->type = NT_TERM_IDENT;
|
||||||
|
node->syms.decl_node = sym;
|
||||||
|
goto END;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
poptok(parser);
|
||||||
|
END:
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ASTNode *parse_subexpression(struct Parser* parser, enum Precedence prec) {
|
||||||
|
enum TokenType ttype;
|
||||||
|
struct expr_prec_table_t* work;
|
||||||
|
struct ASTNode* left;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
work = &expr_table[ttype];
|
||||||
|
// FIXME
|
||||||
|
if (ttype == TOKEN_SEMICOLON || ttype == TOKEN_R_PAREN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (work == NULL || work->parser == NULL || work->ptype == PREFIX_PARSER) {
|
||||||
|
if (work->parser != NULL) {
|
||||||
|
left = work->parser(parser, NULL);
|
||||||
|
} else {
|
||||||
|
left = parse_primary_expression(parser);
|
||||||
|
}
|
||||||
|
} else if (work->ptype == INFIX_PARSER) {
|
||||||
|
if (work->parser == NULL)
|
||||||
|
break;
|
||||||
|
if (work->prec <= prec)
|
||||||
|
break;
|
||||||
|
left = work->parser(parser, left);
|
||||||
|
}
|
||||||
|
// assert(left != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* parse_expr(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype = peektoktype(parser);
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_NOT:
|
||||||
|
case TOKEN_AND:
|
||||||
|
case TOKEN_L_PAREN:
|
||||||
|
case TOKEN_MUL:
|
||||||
|
case TOKEN_ADD:
|
||||||
|
case TOKEN_SUB:
|
||||||
|
case TOKEN_BIT_NOT:
|
||||||
|
case TOKEN_AND_AND:
|
||||||
|
case TOKEN_CHAR_LITERAL:
|
||||||
|
case TOKEN_INT_LITERAL:
|
||||||
|
case TOKEN_STRING_LITERAL:
|
||||||
|
case TOKEN_ADD_ADD:
|
||||||
|
case TOKEN_SUB_SUB:
|
||||||
|
case TOKEN_SIZEOF:
|
||||||
|
case TOKEN_IDENT:
|
||||||
|
return parse_subexpression(parser, PREC_EXPRESSION);
|
||||||
|
default:
|
||||||
|
error("Want expr but not got %s", get_token_name(ttype));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
120
ccompiler/frontend/parser/ast/func.c
Normal file
120
ccompiler/frontend/parser/ast/func.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "../symtab/symtab.h"
|
||||||
|
#include "ast.h"
|
||||||
|
|
||||||
|
#ifndef FUNC_PARAM_CACHE_SIZE
|
||||||
|
#define FUNC_PARAM_CACHE_SIZE 32 // 合理初始值,可覆盖99%常见情况
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct FuncParamCache {
|
||||||
|
struct Token tokens[FUNC_PARAM_CACHE_SIZE];
|
||||||
|
int read_pos; // 当前读取位置
|
||||||
|
int write_pos; // 写入位置
|
||||||
|
int depth; // 当前缓存深度
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum TokenType peekcachetype(struct FuncParamCache* cache) {
|
||||||
|
return cache->tokens[cache->read_pos++].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 语义分析压入符号表
|
||||||
|
static void parse_params(struct Parser* parser, struct FuncParamCache* cache, struct ASTNode* node) {
|
||||||
|
// = peekcachetype(cache);
|
||||||
|
enum TokenType ttype;
|
||||||
|
// if (ttype != TOKEN_L_PAREN) {
|
||||||
|
// error("function expected '('\n");
|
||||||
|
// }
|
||||||
|
struct ASTNode *params = new_ast_node();
|
||||||
|
node->func.params = params;
|
||||||
|
int params_size = 0;
|
||||||
|
|
||||||
|
while ((ttype = peekcachetype(cache)) != TOKEN_R_PAREN) {
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_COMMA:
|
||||||
|
break;
|
||||||
|
case TOKEN_ELLIPSIS:
|
||||||
|
ttype = peekcachetype(cache);
|
||||||
|
if (ttype != TOKEN_R_PAREN) {
|
||||||
|
error("... must be a last parameter list (expect ')')");
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
error("not implement");
|
||||||
|
break;
|
||||||
|
case TOKEN_IDENT:
|
||||||
|
params->children[params_size++] = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO 使用cache的类型解析
|
||||||
|
// parse_type(parser);
|
||||||
|
// TODO type parse
|
||||||
|
// ttype = peekcachetype(cache);
|
||||||
|
// ttype = peekcachetype(cache);
|
||||||
|
// if (ttype != TOKEN_IDENT) {
|
||||||
|
// node->node_type = NT_DECL_FUNC;
|
||||||
|
// flushpeektok(parser);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// error("function expected ')' or ','\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ASTType check_is_func_decl(struct Parser* parser, struct FuncParamCache* cache) {
|
||||||
|
cache->depth = 1;
|
||||||
|
cache->read_pos = 0;
|
||||||
|
cache->write_pos = 0;
|
||||||
|
|
||||||
|
while (cache->depth) {
|
||||||
|
struct Token* tok = peektok(parser);
|
||||||
|
poptok(parser);
|
||||||
|
if (cache->write_pos >= FUNC_PARAM_CACHE_SIZE - 1) {
|
||||||
|
error("function parameter list too long");
|
||||||
|
}
|
||||||
|
cache->tokens[cache->write_pos++] = *tok;
|
||||||
|
switch (tok->type) {
|
||||||
|
case TOKEN_L_PAREN:
|
||||||
|
cache->depth++;
|
||||||
|
break;
|
||||||
|
case TOKEN_R_PAREN:
|
||||||
|
cache->depth--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (peektoktype(parser)) {
|
||||||
|
case TOKEN_SEMICOLON:
|
||||||
|
poptok(parser);
|
||||||
|
return NT_DECL_FUNC;
|
||||||
|
case TOKEN_L_BRACE:
|
||||||
|
return NT_FUNC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("function define or decl need '{' or ';' but you don't got");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* parse_func(struct Parser* parser) {
|
||||||
|
struct ASTNode* ret_type = parse_type(parser);
|
||||||
|
struct ASTNode* func_name = parse_ident(parser);
|
||||||
|
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->func.ret = ret_type;
|
||||||
|
node->func.name = func_name;
|
||||||
|
|
||||||
|
flushpeektok(parser);
|
||||||
|
expecttok(parser, TOKEN_L_PAREN);
|
||||||
|
struct FuncParamCache cache;
|
||||||
|
node->type = check_is_func_decl(parser, &cache);
|
||||||
|
|
||||||
|
symtab_add_symbol(parser->symtab, func_name->syms.tok.constant.str, node);
|
||||||
|
if (node->type == NT_DECL_FUNC) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab_enter_scope(parser->symtab);
|
||||||
|
parse_params(parser, &cache, node);
|
||||||
|
node->func.body = parse_block(parser);
|
||||||
|
symtab_leave_scope(parser->symtab);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
29
ccompiler/frontend/parser/ast/program.c
Normal file
29
ccompiler/frontend/parser/ast/program.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "ast.h"
|
||||||
|
|
||||||
|
#ifndef PROG_MAX_NODE_SIZE
|
||||||
|
#define PROG_MAX_NODE_SIZE (1024 * 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void parse_prog(struct Parser* parser) {
|
||||||
|
/**
|
||||||
|
* Program := (Declaration | Definition)*
|
||||||
|
* same as
|
||||||
|
* Program := Declaration* Definition*
|
||||||
|
*/
|
||||||
|
int child_size = 0;
|
||||||
|
parser->root = new_ast_node();
|
||||||
|
struct ASTNode* node;
|
||||||
|
parser->root->root.children = xmalloc(sizeof(struct ASTNode*) * PROG_MAX_NODE_SIZE);
|
||||||
|
while (1) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
if (peektoktype(parser) == TOKEN_EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = parse_decl(parser);
|
||||||
|
parser->root->root.children[child_size++] = node;
|
||||||
|
}
|
||||||
|
parser->root->type = NT_ROOT;
|
||||||
|
parser->root->root.child_size = child_size;
|
||||||
|
return;
|
||||||
|
}
|
240
ccompiler/frontend/parser/ast/stmt.c
Normal file
240
ccompiler/frontend/parser/ast/stmt.c
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "ast.h"
|
||||||
|
|
||||||
|
struct ASTNode* parse_stmt(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype = peektoktype(parser);
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
switch (ttype) {
|
||||||
|
case TOKEN_IF: {
|
||||||
|
/**
|
||||||
|
* if (exp) stmt
|
||||||
|
* if (exp) stmt else stmt
|
||||||
|
*/
|
||||||
|
poptok(parser);
|
||||||
|
|
||||||
|
expecttok(parser, TOKEN_L_PAREN);
|
||||||
|
node->if_stmt.cond = parse_expr(parser);
|
||||||
|
flushpeektok(parser);
|
||||||
|
expecttok(parser, TOKEN_R_PAREN);
|
||||||
|
|
||||||
|
node->if_stmt.if_stmt = parse_stmt(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype == TOKEN_ELSE) {
|
||||||
|
poptok(parser);
|
||||||
|
node->if_stmt.else_stmt = parse_stmt(parser);
|
||||||
|
} else {
|
||||||
|
node->if_stmt.else_stmt = NULL;
|
||||||
|
}
|
||||||
|
node->type = NT_STMT_IF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_SWITCH: {
|
||||||
|
/**
|
||||||
|
* switch (exp) stmt
|
||||||
|
*/
|
||||||
|
poptok(parser);
|
||||||
|
|
||||||
|
expecttok(parser, TOKEN_L_PAREN);
|
||||||
|
node->switch_stmt.cond = parse_expr(parser);
|
||||||
|
expecttok(parser, TOKEN_R_PAREN);
|
||||||
|
|
||||||
|
node->switch_stmt.body = parse_stmt(parser);
|
||||||
|
node->type = NT_STMT_SWITCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_WHILE: {
|
||||||
|
/**
|
||||||
|
* while (exp) stmt
|
||||||
|
*/
|
||||||
|
poptok(parser);
|
||||||
|
|
||||||
|
expecttok(parser, TOKEN_L_PAREN);
|
||||||
|
node->while_stmt.cond = parse_expr(parser);
|
||||||
|
expecttok(parser, TOKEN_R_PAREN);
|
||||||
|
|
||||||
|
node->while_stmt.body = parse_stmt(parser);
|
||||||
|
node->type = NT_STMT_WHILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_DO: {
|
||||||
|
/**
|
||||||
|
* do stmt while (exp)
|
||||||
|
*/
|
||||||
|
poptok(parser);
|
||||||
|
node->do_while_stmt.body = parse_stmt(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_WHILE) {
|
||||||
|
error("expected while after do");
|
||||||
|
}
|
||||||
|
poptok(parser);
|
||||||
|
expecttok(parser, TOKEN_L_PAREN);
|
||||||
|
node->do_while_stmt.cond = parse_expr(parser);
|
||||||
|
expecttok(parser, TOKEN_R_PAREN);
|
||||||
|
node->type = NT_STMT_DOWHILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_FOR: {
|
||||||
|
/**
|
||||||
|
* for (init; [cond]; [iter]) stmt
|
||||||
|
*/
|
||||||
|
// node->children.stmt.for_stmt.init
|
||||||
|
poptok(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_L_PAREN) {
|
||||||
|
error("expected ( after for");
|
||||||
|
}
|
||||||
|
poptok(parser);
|
||||||
|
|
||||||
|
// init expr or init decl_var
|
||||||
|
// TODO need add this feature
|
||||||
|
node->for_stmt.init = parse_expr(parser);
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
|
||||||
|
// cond expr or null
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_SEMICOLON) {
|
||||||
|
node->for_stmt.cond = parse_expr(parser);
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
} else {
|
||||||
|
node->for_stmt.cond = NULL;
|
||||||
|
poptok(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// iter expr or null
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_R_PAREN) {
|
||||||
|
node->for_stmt.iter = parse_expr(parser);
|
||||||
|
expecttok(parser, TOKEN_R_PAREN);
|
||||||
|
} else {
|
||||||
|
node->for_stmt.iter = NULL;
|
||||||
|
poptok(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->for_stmt.body = parse_stmt(parser);
|
||||||
|
node->type = NT_STMT_FOR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_BREAK: {
|
||||||
|
/**
|
||||||
|
* break ;
|
||||||
|
*/
|
||||||
|
// TODO check 导致外围 for、while 或 do-while 循环或 switch 语句终止。
|
||||||
|
poptok(parser);
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
|
||||||
|
node->type = NT_STMT_BREAK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_CONTINUE: {
|
||||||
|
/**
|
||||||
|
* continue ;
|
||||||
|
*/
|
||||||
|
// TODO check 导致跳过整个 for、 while 或 do-while 循环体的剩余部分。
|
||||||
|
poptok(parser);
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
|
||||||
|
node->type = NT_STMT_CONTINUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_RETURN: {
|
||||||
|
/**
|
||||||
|
* return [exp] ;
|
||||||
|
*/
|
||||||
|
// TODO 终止当前函数并返回指定值给调用方函数。
|
||||||
|
poptok(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_SEMICOLON) {
|
||||||
|
node->return_stmt.expr_stmt = parse_expr(parser);
|
||||||
|
flushpeektok(parser);
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
} else {
|
||||||
|
node->return_stmt.expr_stmt = NULL;
|
||||||
|
}
|
||||||
|
poptok(parser);
|
||||||
|
node->type = NT_STMT_RETURN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_GOTO: {
|
||||||
|
/**
|
||||||
|
* goto label ;
|
||||||
|
*/
|
||||||
|
// TODO check label 将控制无条件转移到所欲位置。
|
||||||
|
//在无法用约定的构造将控制转移到所欲位置时使用。
|
||||||
|
poptok(parser);
|
||||||
|
// find symbol table
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_IDENT) {
|
||||||
|
error("expect identifier after goto");
|
||||||
|
}
|
||||||
|
expecttok(parser, TOKEN_SEMICOLON);
|
||||||
|
// TODO filling label
|
||||||
|
node->goto_stmt.label = parse_ident(parser);
|
||||||
|
node->type = NT_STMT_GOTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_SEMICOLON: {
|
||||||
|
/**
|
||||||
|
* ;
|
||||||
|
* empty stmt using by :
|
||||||
|
* while () ;
|
||||||
|
* if () ;
|
||||||
|
* for () ;
|
||||||
|
*/
|
||||||
|
poptok(parser);
|
||||||
|
node->type = NT_STMT_EMPTY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_L_BRACE: {
|
||||||
|
/**
|
||||||
|
* stmt_block like: { (decl_var | stmt) ... }
|
||||||
|
*/
|
||||||
|
node->block_stmt.block = parse_block(parser);
|
||||||
|
node->type = NT_STMT_BLOCK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_IDENT: {
|
||||||
|
// TODO label goto
|
||||||
|
if (peektoktype(parser) != TOKEN_COLON) {
|
||||||
|
goto EXP;
|
||||||
|
}
|
||||||
|
node->label_stmt.label = parse_ident(parser);
|
||||||
|
expecttok(parser, TOKEN_COLON);
|
||||||
|
node->type = NT_STMT_LABEL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_CASE: {
|
||||||
|
// TODO label switch
|
||||||
|
poptok(parser);
|
||||||
|
error("unimplemented switch label");
|
||||||
|
node->label_stmt.label = parse_expr(parser);
|
||||||
|
// TODO 该表达式为const int
|
||||||
|
expecttok(parser, TOKEN_COLON);
|
||||||
|
node->type = NT_STMT_CASE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_DEFAULT: {
|
||||||
|
// TODO label switch default
|
||||||
|
poptok(parser);
|
||||||
|
expecttok(parser, TOKEN_COLON);
|
||||||
|
node->type = NT_STMT_DEFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
/**
|
||||||
|
* exp ;
|
||||||
|
*/
|
||||||
|
EXP:
|
||||||
|
node->expr_stmt.expr_stmt = parse_expr(parser);
|
||||||
|
flushpeektok(parser);
|
||||||
|
ttype = peektoktype(parser);
|
||||||
|
if (ttype != TOKEN_SEMICOLON) {
|
||||||
|
error("exp must end with \";\"");
|
||||||
|
}
|
||||||
|
poptok(parser);
|
||||||
|
node->type = NT_STMT_EXPR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
182
ccompiler/frontend/parser/ast/term.c
Normal file
182
ccompiler/frontend/parser/ast/term.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "../type.h"
|
||||||
|
#include "ast.h"
|
||||||
|
|
||||||
|
// /* 状态跳转表定义 */
|
||||||
|
// typedef void (*StateHandler)(struct Parser*, struct ASTNode**);
|
||||||
|
|
||||||
|
// enum TypeParseState {
|
||||||
|
// TPS_BASE_TYPE, // 解析基础类型 (int/char等)
|
||||||
|
// TPS_QUALIFIER, // 解析限定符 (const/volatile)
|
||||||
|
// TPS_POINTER, // 解析指针 (*)
|
||||||
|
// TPS_ARRAY, // 解析数组维度 ([n])
|
||||||
|
// TPS_FUNC_PARAMS, // 解析函数参数列表
|
||||||
|
// TPS_END,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// ;
|
||||||
|
|
||||||
|
// /* 状态处理函数前置声明 */
|
||||||
|
// static void handle_base_type(struct Parser*, struct ASTNode**);
|
||||||
|
// static void handle_qualifier(struct Parser*, struct ASTNode**);
|
||||||
|
// static void handle_pointer(struct Parser*, struct ASTNode**);
|
||||||
|
// static void handle_array(struct Parser*, struct ASTNode**);
|
||||||
|
// static void handle_func_params(struct Parser*, struct ASTNode**);
|
||||||
|
// static void handle_error(struct Parser*, struct ASTNode**);
|
||||||
|
|
||||||
|
// /* 状态跳转表(核心优化部分) */
|
||||||
|
// static const struct StateTransition {
|
||||||
|
// enum TokenType tok; // 触发token
|
||||||
|
// StateHandler handler; // 处理函数
|
||||||
|
// enum TypeParseState next_state; // 下一个状态
|
||||||
|
// } state_table[][8] = {
|
||||||
|
// [TPS_QUALIFIER] = {
|
||||||
|
// {TOKEN_CONST, handle_qualifier, TPS_QUALIFIER},
|
||||||
|
// {TOKEN_VOLATILE, handle_qualifier, TPS_QUALIFIER},
|
||||||
|
// {TOKEN_VOID, handle_base_type, TPS_POINTER},
|
||||||
|
// {TOKEN_CHAR, handle_base_type, TPS_POINTER},
|
||||||
|
// {TOKEN_INT, handle_base_type, TPS_POINTER},
|
||||||
|
// {TOKEN_EOF, handle_error, TPS_QUALIFIER},
|
||||||
|
// /* 其他token默认处理 */
|
||||||
|
// {0, NULL, TPS_BASE_TYPE}
|
||||||
|
// },
|
||||||
|
// [TPS_BASE_TYPE] = {
|
||||||
|
// {TOKEN_MUL, handle_pointer, TPS_POINTER},
|
||||||
|
// {TOKEN_L_BRACKET, handle_array, TPS_ARRAY},
|
||||||
|
// {TOKEN_L_PAREN, handle_func_params,TPS_FUNC_PARAMS},
|
||||||
|
// {TOKEN_EOF, NULL, TPS_END},
|
||||||
|
// {0, NULL, TPS_POINTER}
|
||||||
|
// },
|
||||||
|
// [TPS_POINTER] = {
|
||||||
|
// {TOKEN_MUL, handle_pointer, TPS_POINTER},
|
||||||
|
// {TOKEN_L_BRACKET, handle_array, TPS_ARRAY},
|
||||||
|
// {TOKEN_L_PAREN, handle_func_params,TPS_FUNC_PARAMS},
|
||||||
|
// {0, NULL, TPS_END}
|
||||||
|
// },
|
||||||
|
// [TPS_ARRAY] = {
|
||||||
|
// {TOKEN_L_BRACKET, handle_array, TPS_ARRAY},
|
||||||
|
// {TOKEN_L_PAREN, handle_func_params,TPS_FUNC_PARAMS},
|
||||||
|
// {0, NULL, TPS_END}
|
||||||
|
// },
|
||||||
|
// [TPS_FUNC_PARAMS] = {
|
||||||
|
// {0, NULL, TPS_END}
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// /* 新的类型解析函数 */
|
||||||
|
// struct ASTNode* parse_type(struct Parser* p) {
|
||||||
|
// struct ASTNode* type_root = NULL;
|
||||||
|
// struct ASTNode** current = &type_root;
|
||||||
|
// enum TypeParseState state = TPS_QUALIFIER;
|
||||||
|
|
||||||
|
// while (state != TPS_END) {
|
||||||
|
// enum TokenType t = peektoktype(p);
|
||||||
|
// const struct StateTransition* trans = state_table[state];
|
||||||
|
|
||||||
|
// // 查找匹配的转换规则
|
||||||
|
// while (trans->tok != 0 && trans->tok != t) {
|
||||||
|
// trans++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (trans->handler) {
|
||||||
|
// trans->handler(p, current);
|
||||||
|
// } else if (trans->tok == 0) { // 默认规则
|
||||||
|
// state = trans->next_state;
|
||||||
|
// continue;
|
||||||
|
// } else {
|
||||||
|
// error("syntax error type parse error");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// state = trans->next_state;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return type_root;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* 具体状态处理函数实现 */
|
||||||
|
// static void handle_qualifier(struct Parser* p, struct ASTNode** current) {
|
||||||
|
// struct ASTNode* node = new_ast_node();
|
||||||
|
// node->node_type = NT_TYPE_QUAL;
|
||||||
|
// node->data.data_type = poptok(p).type;
|
||||||
|
|
||||||
|
// if (*current) {
|
||||||
|
// (*current)->child.decl.type = node;
|
||||||
|
// } else {
|
||||||
|
// *current = node;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// static void handle_base_type(struct Parser* p, struct ASTNode** current) {
|
||||||
|
// struct ASTNode* node = new_ast_node();
|
||||||
|
// node->node_type = NT_TYPE_BASE;
|
||||||
|
// node->data.data_type = poptok(p).type;
|
||||||
|
|
||||||
|
// // 链接到当前节点链的末端
|
||||||
|
// while (*current && (*current)->child.decl.type) {
|
||||||
|
// current = &(*current)->child.decl.type;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (*current) {
|
||||||
|
// (*current)->child.decl.type = node;
|
||||||
|
// } else {
|
||||||
|
// *current = node;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// static void handle_pointer(struct Parser* p, struct ASTNode** current) {
|
||||||
|
// poptok(p); // 吃掉*
|
||||||
|
// struct ASTNode* node = new_ast_node();
|
||||||
|
// node->node_type = NT_TYPE_PTR;
|
||||||
|
|
||||||
|
// // 插入到当前节点之前
|
||||||
|
// node->child.decl.type = *current;
|
||||||
|
// *current = node;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* 其他处理函数类似实现... */
|
||||||
|
|
||||||
|
struct ASTNode* parser_ident_without_pop(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
struct Token* tok = peektok(parser);
|
||||||
|
if (tok->type != TOKEN_IDENT) {
|
||||||
|
error("syntax error: want identifier but got %d", tok->type);
|
||||||
|
}
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = NT_TERM_IDENT;
|
||||||
|
node->syms.tok = *tok;
|
||||||
|
node->syms.decl_node = NULL;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* parse_ident(struct Parser* parser) {
|
||||||
|
struct ASTNode* node = parser_ident_without_pop(parser);
|
||||||
|
poptok(parser);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* parse_type(struct Parser* parser) {
|
||||||
|
flushpeektok(parser);
|
||||||
|
enum TokenType ttype = peektoktype(parser);
|
||||||
|
enum DataType dtype;
|
||||||
|
switch(ttype) {
|
||||||
|
case TOKEN_VOID: dtype = TYPE_VOID; break;
|
||||||
|
case TOKEN_CHAR: dtype = TYPE_CHAR; break;
|
||||||
|
case TOKEN_SHORT: dtype = TYPE_SHORT; break;
|
||||||
|
case TOKEN_INT: dtype = TYPE_INT; break;
|
||||||
|
case TOKEN_LONG: dtype = TYPE_LONG; break;
|
||||||
|
case TOKEN_FLOAT: dtype = TYPE_FLOAT; break;
|
||||||
|
case TOKEN_DOUBLE: dtype = TYPE_DOUBLE; break;
|
||||||
|
default:
|
||||||
|
error("无效的类型说明符");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ASTNode* node = new_ast_node();
|
||||||
|
node->type = NT_TERM_TYPE;
|
||||||
|
// node->data.data_type = dtype;
|
||||||
|
poptok(parser);
|
||||||
|
|
||||||
|
if (peektoktype(parser) == TOKEN_MUL) {
|
||||||
|
poptok(parser);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
136
ccompiler/frontend/parser/ast/type.c
Normal file
136
ccompiler/frontend/parser/ast/type.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "../type.h"
|
||||||
|
|
||||||
|
enum TypeParseState {
|
||||||
|
TPS_BASE_TYPE, // 解析基础类型 (int/char等)
|
||||||
|
TPS_QUALIFIER, // 解析限定符 (const/volatile)
|
||||||
|
TPS_POINTER, // 解析指针 (*)
|
||||||
|
TPS_ARRAY, // 解析数组维度 ([n])
|
||||||
|
TPS_FUNC_PARAMS // 解析函数参数列表
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ASTNode* parse_type(struct Parser* p) {
|
||||||
|
struct ASTNode* type_root = new_ast_node();
|
||||||
|
struct ASTNode* current = type_root;
|
||||||
|
current->type = NT_TYPE_BASE;
|
||||||
|
|
||||||
|
enum TypeParseState state = TPS_QUALIFIER;
|
||||||
|
int pointer_level = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
enum TokenType t = peektoktype(p);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
// 基础类型解析 (int, char等)
|
||||||
|
case TPS_BASE_TYPE:
|
||||||
|
if (is_base_type(t)) {
|
||||||
|
// current->data.data_type = token_to_datatype(t);
|
||||||
|
poptok(p);
|
||||||
|
state = TPS_POINTER;
|
||||||
|
} else {
|
||||||
|
error("Expected type specifier");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 类型限定符 (const/volatile)
|
||||||
|
case TPS_QUALIFIER:
|
||||||
|
if (t == TOKEN_CONST || t == TOKEN_VOLATILE) {
|
||||||
|
struct ASTNode* qual_node = new_ast_node();
|
||||||
|
qual_node->type = NT_TYPE_QUAL;
|
||||||
|
qual_node->data.data_type = t; // 复用data_type字段存储限定符
|
||||||
|
current->child.decl.type = qual_node;
|
||||||
|
current = qual_node;
|
||||||
|
poptok(p);
|
||||||
|
} else {
|
||||||
|
state = TPS_BASE_TYPE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 指针解析 (*)
|
||||||
|
case TPS_POINTER:
|
||||||
|
if (t == TOKEN_MUL) {
|
||||||
|
struct ASTNode* ptr_node = new_ast_node();
|
||||||
|
ptr_node->type = NT_TYPE_PTR;
|
||||||
|
current->child.decl.type = ptr_node;
|
||||||
|
current = ptr_node;
|
||||||
|
pointer_level++;
|
||||||
|
poptok(p);
|
||||||
|
} else {
|
||||||
|
state = TPS_ARRAY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 数组维度 ([n])
|
||||||
|
case TPS_ARRAY:
|
||||||
|
if (t == TOKEN_L_BRACKET) {
|
||||||
|
poptok(p); // 吃掉[
|
||||||
|
struct ASTNode* arr_node = new_ast_node();
|
||||||
|
arr_node->type = NT_TYPE_ARRAY;
|
||||||
|
|
||||||
|
// 解析数组大小(仅语法检查)
|
||||||
|
if (peektoktype(p) != TOKEN_R_BRACKET) {
|
||||||
|
parse_expr(p); // 不计算实际值
|
||||||
|
}
|
||||||
|
|
||||||
|
expecttok(p, TOKEN_R_BRACKET);
|
||||||
|
current->child.decl.type = arr_node;
|
||||||
|
current = arr_node;
|
||||||
|
} else {
|
||||||
|
state = TPS_FUNC_PARAMS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 函数参数列表
|
||||||
|
case TPS_FUNC_PARAMS:
|
||||||
|
if (t == TOKEN_L_PAREN) {
|
||||||
|
struct ASTNode* func_node = new_ast_node();
|
||||||
|
func_node->type = NT_TYPE_FUNC;
|
||||||
|
current->child.decl.type = func_node;
|
||||||
|
|
||||||
|
// 解析参数列表(仅结构,不验证类型)
|
||||||
|
parse_param_list(p, func_node);
|
||||||
|
current = func_node;
|
||||||
|
} else {
|
||||||
|
return type_root; // 类型解析结束
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是基础类型
|
||||||
|
static int is_base_type(enum TokenType t) {
|
||||||
|
return t >= TOKEN_VOID && t <= TOKEN_DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 转换token到数据类型(简化版)
|
||||||
|
// static enum DataType token_to_datatype(enum TokenType t) {
|
||||||
|
// static enum DataType map[] = {
|
||||||
|
// [TOKEN_VOID] = DT_VOID,
|
||||||
|
// [TOKEN_CHAR] = DT_CHAR,
|
||||||
|
// [TOKEN_INT] = DT_INT,
|
||||||
|
// // ...其他类型映射
|
||||||
|
// };
|
||||||
|
// return map[t];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 解析参数列表(轻量级)
|
||||||
|
static void parse_param_list(struct Parser* p, struct ASTNode* func) {
|
||||||
|
expecttok(p, TOKEN_L_PAREN);
|
||||||
|
|
||||||
|
while (peektoktype(p) != TOKEN_R_PAREN) {
|
||||||
|
struct ASTNode* param = parse_type(p); // 递归解析类型
|
||||||
|
|
||||||
|
// 允许可选参数名(仅语法检查)
|
||||||
|
if (peektoktype(p) == TOKEN_IDENT) {
|
||||||
|
poptok(p); // 吃掉参数名
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peektoktype(p) == TOKEN_COMMA) {
|
||||||
|
poptok(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expecttok(p, TOKEN_R_PAREN);
|
||||||
|
}
|
||||||
|
|
67
ccompiler/frontend/parser/parser.c
Normal file
67
ccompiler/frontend/parser/parser.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
#include "type.h"
|
||||||
|
#include "ast/ast.h"
|
||||||
|
|
||||||
|
int poptok(struct Parser* parser) {
|
||||||
|
if (parser->size == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int idx = parser->cur_idx;
|
||||||
|
parser->cur_idx = (idx + 1) % PARSER_MAX_TOKEN_QUEUE;
|
||||||
|
parser->size--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushpeektok(struct Parser* parser) {
|
||||||
|
parser->peek_idx = parser->cur_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Token* peektok(struct Parser* parser) {
|
||||||
|
int idx = parser->peek_idx;
|
||||||
|
idx = (idx + 1) % PARSER_MAX_TOKEN_QUEUE;
|
||||||
|
if (parser->size >= PARSER_MAX_TOKEN_QUEUE) {
|
||||||
|
warn("peek maybe too deep");
|
||||||
|
}
|
||||||
|
if (parser->peek_idx == parser->end_idx) {
|
||||||
|
if (parser->size == PARSER_MAX_TOKEN_QUEUE) {
|
||||||
|
// FIXME
|
||||||
|
error("buffer overflow");
|
||||||
|
}
|
||||||
|
get_valid_token(parser->lexer, &(parser->TokenBuffer[idx]));
|
||||||
|
parser->size++;
|
||||||
|
parser->end_idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->peek_idx = idx;
|
||||||
|
return &(parser->TokenBuffer[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TokenType peektoktype(struct Parser* parser) {
|
||||||
|
return peektok(parser)->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void expecttok(struct Parser* parser, enum TokenType type) {
|
||||||
|
struct Token* tok = peektok(parser);
|
||||||
|
if (tok->type != type) {
|
||||||
|
error("expected tok: %s, got %s", get_token_name(type), get_token_name(tok->type));
|
||||||
|
} else {
|
||||||
|
poptok(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_parser(struct Parser* parser, struct Lexer* lexer, struct SymbolTable* symtab) {
|
||||||
|
parser->cur_node = NULL;
|
||||||
|
parser->root = NULL;
|
||||||
|
|
||||||
|
parser->cur_idx = 0;
|
||||||
|
parser->peek_idx = 0;
|
||||||
|
parser->end_idx = 0;
|
||||||
|
parser->size = 0;
|
||||||
|
parser->lexer = lexer;
|
||||||
|
parser->symtab = symtab;
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_parser(struct Parser* parser) {
|
||||||
|
parse_prog(parser);
|
||||||
|
}
|
33
ccompiler/frontend/parser/parser.h
Normal file
33
ccompiler/frontend/parser/parser.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef __PARSER_H__
|
||||||
|
#define __PARSER_H__
|
||||||
|
|
||||||
|
#include "../frontend.h"
|
||||||
|
#include "../lexer/lexer.h"
|
||||||
|
// #include "symbol_table/symtab.h"
|
||||||
|
// #include "ast/ast.h"
|
||||||
|
|
||||||
|
#define PARSER_MAX_TOKEN_QUEUE 16
|
||||||
|
|
||||||
|
struct Parser {
|
||||||
|
struct ASTNode* root;
|
||||||
|
struct ASTNode* cur_node;
|
||||||
|
|
||||||
|
struct Lexer* lexer;
|
||||||
|
struct SymbolTable* symtab;
|
||||||
|
int cur_idx;
|
||||||
|
int peek_idx;
|
||||||
|
int end_idx;
|
||||||
|
int size;
|
||||||
|
struct Token TokenBuffer[PARSER_MAX_TOKEN_QUEUE];
|
||||||
|
int err_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_parser(struct Parser* parser, struct Lexer* lexer, struct SymbolTable* symtab);
|
||||||
|
void run_parser(struct Parser* parser);
|
||||||
|
void flushpeektok(struct Parser* parser);
|
||||||
|
int poptok(struct Parser* parser);
|
||||||
|
struct Token* peektok(struct Parser* parser);
|
||||||
|
enum TokenType peektoktype(struct Parser* parser);
|
||||||
|
void expecttok(struct Parser* parser, enum TokenType type);
|
||||||
|
|
||||||
|
#endif
|
53
ccompiler/frontend/parser/symtab/hashmap.c
Normal file
53
ccompiler/frontend/parser/symtab/hashmap.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// hashmap.c
|
||||||
|
#include "hashmap.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// DJB2哈希算法
|
||||||
|
static unsigned long hash(const char* str) {
|
||||||
|
unsigned long hash = 5381;
|
||||||
|
int c;
|
||||||
|
while ((c = *str++))
|
||||||
|
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||||
|
return hash % HMAP_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmap_init(HashMap* map) {
|
||||||
|
memset(map->buckets, 0, sizeof(map->buckets));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmap_put(HashMap* map, const char* key, void* value) {
|
||||||
|
unsigned long idx = hash(key);
|
||||||
|
HashMapEntry* entry = malloc(sizeof(HashMapEntry));
|
||||||
|
entry->key = strdup(key);
|
||||||
|
entry->value = value;
|
||||||
|
entry->next = map->buckets[idx];
|
||||||
|
map->buckets[idx] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hmap_get(HashMap* map, const char* key) {
|
||||||
|
unsigned long idx = hash(key);
|
||||||
|
HashMapEntry* entry = map->buckets[idx];
|
||||||
|
while (entry) {
|
||||||
|
if (strcmp(entry->key, key) == 0)
|
||||||
|
return entry->value;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hmap_contains(HashMap* map, const char* key) {
|
||||||
|
return hmap_get(map, key) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmap_destroy(HashMap* map) {
|
||||||
|
for (int i = 0; i < HMAP_SIZE; i++) {
|
||||||
|
HashMapEntry* entry = map->buckets[i];
|
||||||
|
while (entry) {
|
||||||
|
HashMapEntry* next = entry->next;
|
||||||
|
free(entry->key);
|
||||||
|
free(entry);
|
||||||
|
entry = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
ccompiler/frontend/parser/symtab/hashmap.h
Normal file
31
ccompiler/frontend/parser/symtab/hashmap.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef HASHMAP_H
|
||||||
|
#define HASHMAP_H
|
||||||
|
|
||||||
|
#define HMAP_SIZE 64
|
||||||
|
|
||||||
|
typedef struct HashMapEntry {
|
||||||
|
char* key;
|
||||||
|
void* value;
|
||||||
|
struct HashMapEntry* next;
|
||||||
|
} HashMapEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HashMapEntry* buckets[HMAP_SIZE];
|
||||||
|
} HashMap;
|
||||||
|
|
||||||
|
// 初始化哈希表
|
||||||
|
void hmap_init(HashMap* map);
|
||||||
|
|
||||||
|
// 插入键值对
|
||||||
|
void hmap_put(HashMap* map, const char* key, void* value);
|
||||||
|
|
||||||
|
// 查找键值
|
||||||
|
void* hmap_get(HashMap* map, const char* key);
|
||||||
|
|
||||||
|
// 检查键是否存在
|
||||||
|
int hmap_contains(HashMap* map, const char* key);
|
||||||
|
|
||||||
|
// 释放哈希表内存(不释放value)
|
||||||
|
void hmap_destroy(HashMap* map);
|
||||||
|
|
||||||
|
#endif
|
43
ccompiler/frontend/parser/symtab/scope.c
Normal file
43
ccompiler/frontend/parser/symtab/scope.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// scope.c
|
||||||
|
#include "scope.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct Scope Scope;
|
||||||
|
|
||||||
|
Scope* scope_create(Scope* parent) {
|
||||||
|
Scope* scope = malloc(sizeof(Scope));
|
||||||
|
hmap_init(&scope->symbols);
|
||||||
|
scope->parent = parent;
|
||||||
|
scope->base_offset = 0;
|
||||||
|
scope->cur_offset = 0;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scope_destroy(Scope* scope) {
|
||||||
|
hmap_destroy(&scope->symbols);
|
||||||
|
free(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scope_insert(Scope* scope, const char* name, void* symbol) {
|
||||||
|
if (hmap_contains(&scope->symbols, name)) {
|
||||||
|
// 处理重复定义错误
|
||||||
|
fprintf(stderr, "Error: Symbol '%s' already defined\n", name);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
hmap_put(&scope->symbols, name, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* scope_lookup(Scope* scope, const char* name) {
|
||||||
|
void* symbol = NULL;
|
||||||
|
while (scope) {
|
||||||
|
symbol = hmap_get(&scope->symbols, name);
|
||||||
|
if (symbol) break;
|
||||||
|
scope = scope->parent;
|
||||||
|
}
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* scope_lookup_current(Scope* scope, const char* name) {
|
||||||
|
return hmap_get(&scope->symbols, name);
|
||||||
|
}
|
28
ccompiler/frontend/parser/symtab/scope.h
Normal file
28
ccompiler/frontend/parser/symtab/scope.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef SCOPE_H
|
||||||
|
#define SCOPE_H
|
||||||
|
|
||||||
|
#include "hashmap.h"
|
||||||
|
|
||||||
|
struct Scope {
|
||||||
|
HashMap symbols; // 当前作用域符号表
|
||||||
|
struct Scope* parent; // 上层作用域
|
||||||
|
int base_offset;
|
||||||
|
int cur_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建新作用域(父作用域可为NULL)
|
||||||
|
struct Scope* scope_create(struct Scope* parent);
|
||||||
|
|
||||||
|
// 销毁作用域
|
||||||
|
void scope_destroy(struct Scope* scope);
|
||||||
|
|
||||||
|
// 在当前作用域插入符号
|
||||||
|
void scope_insert(struct Scope* scope, const char* name, void* symbol);
|
||||||
|
|
||||||
|
// 逐级查找符号
|
||||||
|
void* scope_lookup(struct Scope* scope, const char* name);
|
||||||
|
|
||||||
|
// 仅在当前作用域查找
|
||||||
|
void* scope_lookup_current(struct Scope* scope, const char* name);
|
||||||
|
|
||||||
|
#endif
|
45
ccompiler/frontend/parser/symtab/symtab.c
Normal file
45
ccompiler/frontend/parser/symtab/symtab.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// symtab.c
|
||||||
|
#include "../../frontend.h"
|
||||||
|
#include "scope.h"
|
||||||
|
#include "symtab.h"
|
||||||
|
|
||||||
|
typedef struct SymbolTable SymbolTable;
|
||||||
|
typedef struct Scope Scope;
|
||||||
|
|
||||||
|
void init_symtab(SymbolTable* symtab) {
|
||||||
|
symtab->global_scope = scope_create(NULL);
|
||||||
|
symtab->cur_scope = symtab->global_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void del_symtab(SymbolTable* symtab) {
|
||||||
|
scope_destroy(symtab->global_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtab_enter_scope(SymbolTable* symtab) {
|
||||||
|
struct Scope* scope = scope_create(symtab->cur_scope);
|
||||||
|
scope->base_offset = symtab->cur_scope->base_offset + symtab->cur_scope->cur_offset;
|
||||||
|
symtab->cur_scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtab_leave_scope(SymbolTable* symtab) {
|
||||||
|
Scope * scope = symtab->cur_scope;
|
||||||
|
if (scope == NULL) {
|
||||||
|
error("cannot leave NULL scope or global scope");
|
||||||
|
}
|
||||||
|
symtab->cur_scope = symtab->cur_scope->parent;
|
||||||
|
scope_destroy(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void symtab_add_symbol(SymbolTable* symtab, const char* name, void* ast_node) {
|
||||||
|
struct Scope* scope = symtab->cur_scope;
|
||||||
|
if (scope_lookup_current(scope, name) != NULL) {
|
||||||
|
// TODO WARNING
|
||||||
|
// return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope_insert(scope, name, ast_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* symtab_lookup_symbol(SymbolTable* symtab, const char* name) {
|
||||||
|
return scope_lookup(symtab->cur_scope, name);
|
||||||
|
}
|
18
ccompiler/frontend/parser/symtab/symtab.h
Normal file
18
ccompiler/frontend/parser/symtab/symtab.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// symtab.h
|
||||||
|
#ifndef __SYMTAB_H__
|
||||||
|
#define __SYMTAB_H__
|
||||||
|
|
||||||
|
struct SymbolTable {
|
||||||
|
struct Scope* cur_scope;
|
||||||
|
struct Scope* global_scope;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init_symtab(struct SymbolTable* symtab);
|
||||||
|
void del_symtab(struct SymbolTable* symtab);
|
||||||
|
|
||||||
|
void symtab_enter_scope(struct SymbolTable* symtab);
|
||||||
|
void symtab_leave_scope(struct SymbolTable* symtab);
|
||||||
|
void symtab_add_symbol(struct SymbolTable* symtab, const char* name, void* ast_node);
|
||||||
|
void* symtab_lookup_symbol(struct SymbolTable* symtab, const char* name);
|
||||||
|
|
||||||
|
#endif
|
4
ccompiler/frontend/parser/tests/test.c
Normal file
4
ccompiler/frontend/parser/tests/test.c
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
extern int _print_str(const char* str);
|
||||||
|
int main(void) {
|
||||||
|
_print_str("Hello, world!\n");
|
||||||
|
}
|
14
ccompiler/frontend/parser/tests/test_file.c
Normal file
14
ccompiler/frontend/parser/tests/test_file.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
// int __print_str(char* str);
|
||||||
|
int f(void);
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int a;
|
||||||
|
// f();
|
||||||
|
// a = 1 + 2 * 3 + 4;
|
||||||
|
// __print_str("Hello, world!\n");
|
||||||
|
a = 3 - f() * (3 + 2) % 6;
|
||||||
|
// 测试用例:
|
||||||
|
// if (a) if (2) 3; else b;
|
||||||
|
// 是否正确解析为 if (a) { if (b) c else d }
|
||||||
|
}
|
34
ccompiler/frontend/parser/tests/test_parser.c
Normal file
34
ccompiler/frontend/parser/tests/test_parser.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "../parser.h"
|
||||||
|
#include "../ast/ast.h"
|
||||||
|
#include "../symtab/symtab.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// gcc -g ../parser.c ../../lexer/lexer.c ../ast/ast.c ../ast/block.c ../ast/decl.c ../ast/expr.c ../ast/func.c ../ast/program.c ../ast/stmt.c ../ast/term.c ../symtab/hashmap.c ../symtab/scope.c ../symtab/symtab.c test_parser.c -o test_parser
|
||||||
|
// gcc -g test_parser.c -L../.. -lfrontend -o test_parser
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
const char* file_name = "test_file.c";
|
||||||
|
if (argc == 2) {
|
||||||
|
file_name = argv[1];
|
||||||
|
}
|
||||||
|
FILE* fp = fopen(file_name, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
perror("open file failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("open file success\n");
|
||||||
|
|
||||||
|
struct Lexer lexer;
|
||||||
|
init_lexer(&lexer, file_name, fp, (lexer_sread_fn)fread_s);
|
||||||
|
|
||||||
|
struct SymbolTable symtab;
|
||||||
|
init_symtab(&symtab);
|
||||||
|
|
||||||
|
struct Parser parser;
|
||||||
|
init_parser(&parser, &lexer, &symtab);
|
||||||
|
parse_prog(&parser);
|
||||||
|
|
||||||
|
printf("parse_end\n");
|
||||||
|
pnt_ast(parser.root, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
35
ccompiler/frontend/parser/type.h
Normal file
35
ccompiler/frontend/parser/type.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef __TYPE_H__
|
||||||
|
#define __TYPE_H__
|
||||||
|
|
||||||
|
#include "../lexer/token.h"
|
||||||
|
|
||||||
|
enum DataType {
|
||||||
|
TYPE_VOID,
|
||||||
|
TYPE_CHAR,
|
||||||
|
TYPE_SHORT,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_LONG,
|
||||||
|
TYPE_LONG_LONG,
|
||||||
|
TYPE_FLOAT,
|
||||||
|
TYPE_DOUBLE,
|
||||||
|
TYPE_LONG_DOUBLE,
|
||||||
|
|
||||||
|
// prefix
|
||||||
|
TYPE_SIGNED,
|
||||||
|
TYPE_UNSIGNED,
|
||||||
|
// TYPE_BOOL,
|
||||||
|
// TYPE_COMPLEX,
|
||||||
|
// TYPE_IMAGINARY,
|
||||||
|
|
||||||
|
TYPE_ENUM,
|
||||||
|
TYPE_ARRAY,
|
||||||
|
TYPE_STRUCT,
|
||||||
|
TYPE_UNION,
|
||||||
|
TYPE_FUNCTION,
|
||||||
|
TYPE_POINTER,
|
||||||
|
TYPE_ATOMIC,
|
||||||
|
|
||||||
|
TYPE_TYPEDEF,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
299
ccompiler/middleend/ir.c
Normal file
299
ccompiler/middleend/ir.c
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#include "ir.h"
|
||||||
|
#include "../frontend/frontend.h"
|
||||||
|
|
||||||
|
typedef struct ASTNode ASTNode;
|
||||||
|
|
||||||
|
// 上下文结构,记录生成过程中的状态
|
||||||
|
typedef struct {
|
||||||
|
ir_func_t* current_func; // 当前处理的函数
|
||||||
|
ir_bblock_t* current_block; // 当前基本块
|
||||||
|
uint32_t vreg_counter; // 虚拟寄存器计数器
|
||||||
|
} IRGenContext;
|
||||||
|
IRGenContext ctx;
|
||||||
|
ir_prog_t prog;
|
||||||
|
ir_type_t type_i32 = {
|
||||||
|
.tag = IR_TYPE_INT32,
|
||||||
|
};
|
||||||
|
static inline void init_ir_node_t(ir_node_t* node) {
|
||||||
|
vector_init(node->used_by);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ir_node_t* new_ir_node_t() {
|
||||||
|
ir_node_t* node = xmalloc(sizeof(ir_node_t));
|
||||||
|
init_ir_node_t(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_node_t* emit_instr(ir_bblock_t* block) {
|
||||||
|
if (block == NULL) block = ctx.current_block;
|
||||||
|
ir_node_t *node = new_ir_node_t();
|
||||||
|
vector_push(block->instrs, node);
|
||||||
|
return vector_at(block->instrs, block->instrs.size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit_br(ir_node_t cond, const char* true_lable, const char* false_lable) {
|
||||||
|
ir_node_t br = {
|
||||||
|
.tag = IR_NODE_RET,
|
||||||
|
.data = {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// emit_instr(br, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_node_t* gen_ir_expr(ASTNode* node) {
|
||||||
|
switch (node->type) {
|
||||||
|
case NT_TERM_VAL: {
|
||||||
|
ir_node_t* ir = new_ir_node_t();
|
||||||
|
*ir = (ir_node_t) {
|
||||||
|
.tag = IR_NODE_CONST_INT,
|
||||||
|
.data.const_int = {
|
||||||
|
.val = node->syms.tok.constant.i,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
case NT_TERM_IDENT: {
|
||||||
|
ir_node_t* decl = node->syms.decl_node->decl_val.data;
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
case NT_TERM_CALL: {
|
||||||
|
// TODO
|
||||||
|
ir_node_t* ir = new_ir_node_t();
|
||||||
|
*ir = (ir_node_t) {
|
||||||
|
.tag = IR_NODE_CALL,
|
||||||
|
.data.call = {
|
||||||
|
.callee = NULL,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vector_init(ir->data.call.args);
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto NEXT;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
NEXT:
|
||||||
|
ir_node_t* lhs = gen_ir_expr(node->expr.left);
|
||||||
|
ir_node_t* rhs = node->expr.right ? gen_ir_expr(node->expr.right) : NULL;
|
||||||
|
|
||||||
|
if (node->type == NT_COMMA) {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_node_t* instr = emit_instr(NULL);
|
||||||
|
vector_push(lhs->used_by, instr);
|
||||||
|
if (rhs) { vector_push(rhs->used_by, instr); }
|
||||||
|
|
||||||
|
ir_node_t* ret;
|
||||||
|
#define BINOP(operand) do { \
|
||||||
|
*instr = (ir_node_t){ \
|
||||||
|
.tag = IR_NODE_OP, \
|
||||||
|
.data.op = { \
|
||||||
|
.op = operand, \
|
||||||
|
.lhs = lhs, \
|
||||||
|
.rhs = rhs, \
|
||||||
|
}, \
|
||||||
|
}; \
|
||||||
|
ret = instr; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
switch (node->type) {
|
||||||
|
case NT_ADD :// (expr) + (expr)
|
||||||
|
BINOP(IR_OP_ADD);
|
||||||
|
break;
|
||||||
|
case NT_SUB :// (expr) - (expr)
|
||||||
|
BINOP(IR_OP_SUB);
|
||||||
|
break;
|
||||||
|
case NT_MUL :// (expr) * (expr)
|
||||||
|
BINOP(IR_OP_MUL);
|
||||||
|
break;
|
||||||
|
case NT_DIV :// (expr) / (expr)
|
||||||
|
BINOP(IR_OP_DIV);
|
||||||
|
break;
|
||||||
|
case NT_MOD :// (expr) % (expr)
|
||||||
|
BINOP(IR_OP_MOD);
|
||||||
|
break;
|
||||||
|
case NT_AND :// (expr) & (expr)
|
||||||
|
BINOP(IR_OP_AND);
|
||||||
|
break;
|
||||||
|
case NT_OR :// (expr) | (expr)
|
||||||
|
BINOP(IR_OP_OR);
|
||||||
|
break;
|
||||||
|
case NT_XOR :// (expr) ^ (expr)
|
||||||
|
BINOP(IR_OP_XOR);
|
||||||
|
break;
|
||||||
|
case NT_BIT_NOT :// ~ (expr)
|
||||||
|
// TODO
|
||||||
|
// BINOP(IR_OP_NOT);
|
||||||
|
break;
|
||||||
|
case NT_L_SH :// (expr) << (expr)
|
||||||
|
BINOP(IR_OP_SHL);
|
||||||
|
break;
|
||||||
|
case NT_R_SH :// (expr) >> (expr)
|
||||||
|
BINOP(IR_OP_SHR); // Shift right logical.
|
||||||
|
// TODO
|
||||||
|
// BINOP(IR_OP_SAR); // Shift right arithmetic.
|
||||||
|
break;
|
||||||
|
case NT_EQ :// (expr) == (expr)
|
||||||
|
BINOP(IR_OP_EQ);
|
||||||
|
break;
|
||||||
|
case NT_NEQ :// (expr) != (expr)
|
||||||
|
BINOP(IR_OP_NEQ);
|
||||||
|
break;
|
||||||
|
case NT_LE :// (expr) <= (expr)
|
||||||
|
BINOP(IR_OP_LE);
|
||||||
|
break;
|
||||||
|
case NT_GE :// (expr) >= (expr)
|
||||||
|
BINOP(IR_OP_GE);
|
||||||
|
break;
|
||||||
|
case NT_LT :// (expr) < (expr)
|
||||||
|
BINOP(IR_OP_LT);
|
||||||
|
break;
|
||||||
|
case NT_GT :// (expr) > (expr)
|
||||||
|
BINOP(IR_OP_GE);
|
||||||
|
break;
|
||||||
|
case NT_AND_AND :// (expr) && (expr)
|
||||||
|
break;
|
||||||
|
case NT_OR_OR :// (expr) || (expr)
|
||||||
|
break;
|
||||||
|
case NT_NOT :// ! (expr)
|
||||||
|
ir_node_t* zero = xmalloc(sizeof(ir_node_t));
|
||||||
|
*zero = (ir_node_t){
|
||||||
|
.tag = IR_NODE_CONST_INT,
|
||||||
|
.data.const_int = {
|
||||||
|
.val = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
*instr = (ir_node_t){
|
||||||
|
.tag = IR_NODE_OP,
|
||||||
|
.data.op = {
|
||||||
|
.op = IR_OP_EQ,
|
||||||
|
.lhs = zero,
|
||||||
|
.rhs = lhs,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ret = instr;
|
||||||
|
break;
|
||||||
|
case NT_ASSIGN :// (expr) = (expr)
|
||||||
|
*instr = (ir_node_t){
|
||||||
|
.tag = IR_NODE_STORE,
|
||||||
|
.data.store = {
|
||||||
|
.target = lhs,
|
||||||
|
.value = rhs,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ret = rhs;
|
||||||
|
break;
|
||||||
|
// case NT_COND : // (expr) ? (expr) : (expr)
|
||||||
|
default:
|
||||||
|
// TODO self error msg
|
||||||
|
error("Unsupported IR generation for AST node type %d", node->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gen_ir_from_ast(struct ASTNode* node) {
|
||||||
|
switch (node->type) {
|
||||||
|
case NT_ROOT: {
|
||||||
|
for (int i = 0; i < node->root.child_size; i ++) {
|
||||||
|
gen_ir_from_ast(node->root.children[i]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case NT_FUNC: {
|
||||||
|
ir_func_t *func = xmalloc(sizeof(ir_func_t));
|
||||||
|
*func = (ir_func_t) {
|
||||||
|
.name = node->func.name->syms.tok.constant.str,
|
||||||
|
};
|
||||||
|
vector_init(func->bblocks);
|
||||||
|
|
||||||
|
ir_bblock_t *entry = xmalloc(sizeof(ir_bblock_t));
|
||||||
|
*entry = (ir_bblock_t) {
|
||||||
|
.label = "entry",
|
||||||
|
};
|
||||||
|
vector_init(entry->instrs);
|
||||||
|
vector_push(func->bblocks, entry);
|
||||||
|
|
||||||
|
IRGenContext prev_ctx = ctx;
|
||||||
|
ctx = (IRGenContext) {
|
||||||
|
.current_func = func,
|
||||||
|
.current_block = vector_at(func->bblocks, 0),
|
||||||
|
.vreg_counter = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
gen_ir_from_ast(node->func.body);
|
||||||
|
|
||||||
|
ctx = prev_ctx;
|
||||||
|
vector_push(prog.funcs, func);
|
||||||
|
} break;
|
||||||
|
case NT_STMT_RETURN: {
|
||||||
|
ir_node_t* ret = gen_ir_expr(node->return_stmt.expr_stmt);
|
||||||
|
ir_node_t* ir = emit_instr(NULL);
|
||||||
|
*ir = (ir_node_t) {
|
||||||
|
.tag = IR_NODE_RET,
|
||||||
|
.data = {
|
||||||
|
.ret = {
|
||||||
|
.ret_val = ret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_BLOCK: {
|
||||||
|
for (int i = 0; i < node->block.child_size; i ++) {
|
||||||
|
gen_ir_from_ast(node->block.children[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_STMT_IF: {
|
||||||
|
ir_node_t *cond = gen_ir_expr(node->if_stmt.cond);
|
||||||
|
|
||||||
|
// xmalloc();
|
||||||
|
// ir_bblock_t then_block = {
|
||||||
|
// };
|
||||||
|
node->if_stmt.if_stmt;
|
||||||
|
node->if_stmt.else_stmt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_STMT_WHILE: {
|
||||||
|
node->while_stmt.cond;
|
||||||
|
node->while_stmt.body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_STMT_DOWHILE: {
|
||||||
|
node->do_while_stmt.cond;
|
||||||
|
node->do_while_stmt.body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_STMT_FOR: {
|
||||||
|
node->for_stmt.init;
|
||||||
|
node->for_stmt.cond;
|
||||||
|
node->for_stmt.iter;
|
||||||
|
node->for_stmt.body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_DECL_VAR: {
|
||||||
|
ir_node_t* ret_node = emit_instr(NULL);
|
||||||
|
*ret_node = (ir_node_t) {
|
||||||
|
.tag = IR_NODE_ALLOC,
|
||||||
|
.name = node->decl_val.name->syms.tok.constant.str,
|
||||||
|
.type = &type_i32,
|
||||||
|
};
|
||||||
|
node->decl_val.data = ret_node;
|
||||||
|
if (node->decl_val.expr_stmt != NULL) {
|
||||||
|
gen_ir_from_ast(node->decl_val.expr_stmt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_STMT_EXPR: {
|
||||||
|
gen_ir_expr(node->expr_stmt.expr_stmt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_STMT_EMPTY: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// TODO: 错误处理
|
||||||
|
error("unknown node type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
155
ccompiler/middleend/ir.h
Normal file
155
ccompiler/middleend/ir.h
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// ir_core.h
|
||||||
|
#ifndef IR_CORE_H
|
||||||
|
#define IR_CORE_H
|
||||||
|
|
||||||
|
#include "../../libcore/vector.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// 错误码定义
|
||||||
|
typedef enum {
|
||||||
|
IR_EC_SUCCESS = 0, // 成功
|
||||||
|
IR_EC_MEMORY_ERROR, // 内存分配失败
|
||||||
|
IR_EC_TYPE_MISMATCH, // 类型不匹配
|
||||||
|
IR_EC_INVALID_OPERAND, // 无效操作数
|
||||||
|
IR_EC_DUPLICATE_SYMBOL, // 符号重定义
|
||||||
|
} ir_ecode_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum {
|
||||||
|
IR_TYPE_INT32,
|
||||||
|
IR_TYPE_PTR,
|
||||||
|
IR_TYPE_ARRAY,
|
||||||
|
IR_TYPE_FUNC,
|
||||||
|
IR_TYPE_VOID,
|
||||||
|
} tag;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct ir_type *base;
|
||||||
|
size_t len;
|
||||||
|
} arr;
|
||||||
|
struct {
|
||||||
|
struct ir_type *ret;
|
||||||
|
struct ir_type **params;
|
||||||
|
size_t param_cnt;
|
||||||
|
} func;
|
||||||
|
};
|
||||||
|
} ir_type_t;
|
||||||
|
|
||||||
|
typedef struct ir_node ir_node_t;
|
||||||
|
|
||||||
|
typedef struct ir_bblock {
|
||||||
|
const char *label;
|
||||||
|
vector_header(instrs, ir_node_t*);
|
||||||
|
// ir_arr_t used_by;
|
||||||
|
} ir_bblock_t; // basic block
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
ir_type_t *type;
|
||||||
|
vector_header(params, ir_node_t*);
|
||||||
|
vector_header(bblocks, ir_bblock_t*);
|
||||||
|
} ir_func_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vector_header(global, ir_node_t*);
|
||||||
|
vector_header(funcs, ir_func_t*);
|
||||||
|
} ir_prog_t;
|
||||||
|
|
||||||
|
struct ir_node {
|
||||||
|
const ir_type_t* type;
|
||||||
|
const char* name;
|
||||||
|
vector_header(used_by, ir_node_t*);
|
||||||
|
enum {
|
||||||
|
IR_NODE_CONST_INT,
|
||||||
|
IR_NODE_ALLOC,
|
||||||
|
IR_NODE_LOAD,
|
||||||
|
IR_NODE_STORE,
|
||||||
|
IR_NODE_GET_PTR,
|
||||||
|
IR_NODE_OP,
|
||||||
|
IR_NODE_BRANCH,
|
||||||
|
IR_NODE_JUMP,
|
||||||
|
IR_NODE_CALL,
|
||||||
|
IR_NODE_RET,
|
||||||
|
} tag;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
int32_t val;
|
||||||
|
} const_int;
|
||||||
|
struct {
|
||||||
|
ir_node_t* target;
|
||||||
|
} load;
|
||||||
|
struct {
|
||||||
|
ir_node_t* target;
|
||||||
|
ir_node_t* value;
|
||||||
|
} store;
|
||||||
|
struct {
|
||||||
|
ir_node_t* src_addr;
|
||||||
|
ir_node_t* offset;
|
||||||
|
} get_ptr;
|
||||||
|
struct {
|
||||||
|
enum {
|
||||||
|
/// Not equal to.
|
||||||
|
IR_OP_NEQ,
|
||||||
|
/// Equal to.
|
||||||
|
IR_OP_EQ,
|
||||||
|
/// Greater than.
|
||||||
|
IR_OP_GT,
|
||||||
|
/// Less than.
|
||||||
|
IR_OP_LT,
|
||||||
|
/// Greater than or equal to.
|
||||||
|
IR_OP_GE,
|
||||||
|
/// Less than or equal to.
|
||||||
|
IR_OP_LE,
|
||||||
|
/// Addition.
|
||||||
|
IR_OP_ADD,
|
||||||
|
/// Subtraction.
|
||||||
|
IR_OP_SUB,
|
||||||
|
/// Multiplication.
|
||||||
|
IR_OP_MUL,
|
||||||
|
/// Division.
|
||||||
|
IR_OP_DIV,
|
||||||
|
/// Modulo.
|
||||||
|
IR_OP_MOD,
|
||||||
|
/// Bitwise AND.
|
||||||
|
IR_OP_AND,
|
||||||
|
/// Bitwise OR.
|
||||||
|
IR_OP_OR,
|
||||||
|
/// Bitwise XOR.
|
||||||
|
IR_OP_XOR,
|
||||||
|
/// Bitwise NOT.
|
||||||
|
IR_OP_NOT,
|
||||||
|
/// Shift left logical.
|
||||||
|
IR_OP_SHL,
|
||||||
|
/// Shift right logical.
|
||||||
|
IR_OP_SHR,
|
||||||
|
/// Shift right arithmetic.
|
||||||
|
IR_OP_SAR,
|
||||||
|
} op;
|
||||||
|
ir_node_t* lhs;
|
||||||
|
ir_node_t* rhs;
|
||||||
|
} op;
|
||||||
|
struct {
|
||||||
|
ir_node_t* cond;
|
||||||
|
ir_bblock_t true_bblock;
|
||||||
|
ir_bblock_t false_bblock;
|
||||||
|
} branch;
|
||||||
|
struct {
|
||||||
|
ir_bblock_t target_bblock;
|
||||||
|
} jump;
|
||||||
|
struct {
|
||||||
|
ir_func_t callee;
|
||||||
|
vector_header(args, ir_node_t);
|
||||||
|
} call;
|
||||||
|
struct {
|
||||||
|
ir_node_t* ret_val;
|
||||||
|
} ret;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ir_prog_t prog;
|
||||||
|
struct ASTNode;
|
||||||
|
void gen_ir_from_ast(struct ASTNode* node);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // IR_CORE_H
|
0
ccompiler/middleend/reg_alloc.c
Normal file
0
ccompiler/middleend/reg_alloc.c
Normal file
8
ccompiler/middleend/reg_alloc.h
Normal file
8
ccompiler/middleend/reg_alloc.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef __REG_ALLOC_H__
|
||||||
|
#define __REG_ALLOC_H__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} reg_alloc_t;
|
||||||
|
|
||||||
|
#endif
|
8
ccompiler/middleend/tests/Makefile
Normal file
8
ccompiler/middleend/tests/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
all: test_ir
|
||||||
|
|
||||||
|
|
||||||
|
test_ir: frontend
|
||||||
|
gcc -g ../ir.c test_ir.c -L../../frontend -lfrontend -o test_ir
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
make -C ../../frontend
|
5
ccompiler/middleend/tests/test_file.c
Normal file
5
ccompiler/middleend/tests/test_file.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int main(void) {
|
||||||
|
int a;
|
||||||
|
a = 1 + 2 * 3;
|
||||||
|
return a;
|
||||||
|
}
|
18
ccompiler/middleend/tests/test_ir.c
Normal file
18
ccompiler/middleend/tests/test_ir.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "../ir.h"
|
||||||
|
#include "../../frontend/frontend.h"
|
||||||
|
|
||||||
|
int main(int argc, const char** argv) {
|
||||||
|
const char* file_name = "test_file.c";
|
||||||
|
if (argc == 2) {
|
||||||
|
file_name = argv[1];
|
||||||
|
}
|
||||||
|
FILE* fp = fopen(file_name, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
perror("open file failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("open file success\n");
|
||||||
|
struct ASTNode* root = frontend("test.c", fp, (sread_fn)fread_s);
|
||||||
|
gen_ir_from_ast(root);
|
||||||
|
return 0;
|
||||||
|
}
|
1994
libcore/acutest.h
Normal file
1994
libcore/acutest.h
Normal file
File diff suppressed because it is too large
Load Diff
10
libcore/libcore.h
Normal file
10
libcore/libcore.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __STDCORE_H__
|
||||||
|
#define __STDCORE_H__
|
||||||
|
|
||||||
|
#ifndef __NO_LINK_STDLIB
|
||||||
|
#include <stdlib.h>
|
||||||
|
#else
|
||||||
|
#error "__NO_LINK_STDLIB"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
202
libcore/vector-gdb.py
Normal file
202
libcore/vector-gdb.py
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
# # vector_gdb.py
|
||||||
|
# import gdb
|
||||||
|
# import re
|
||||||
|
|
||||||
|
# class VectorPrinter:
|
||||||
|
# """解析宏定义的 vector 结构体"""
|
||||||
|
|
||||||
|
# def __init__(self, val):
|
||||||
|
# self.val = val
|
||||||
|
|
||||||
|
# def check_vector_type(self):
|
||||||
|
# """验证是否为合法 vector 结构体"""
|
||||||
|
# try:
|
||||||
|
# # 检查是否包含 size/cap/data 字段
|
||||||
|
# return all(self.val.type.has_key(field)
|
||||||
|
# for field in ['size', 'cap', 'data'])
|
||||||
|
# except gdb.error:
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# def get_array_view(self):
|
||||||
|
# """将 data 字段转换为数组视图"""
|
||||||
|
# if not self.check_vector_type():
|
||||||
|
# return None
|
||||||
|
|
||||||
|
# cap = int(self.val['cap'])
|
||||||
|
# data_ptr = self.val['data']
|
||||||
|
|
||||||
|
# if cap == 0 or data_ptr == 0:
|
||||||
|
# return []
|
||||||
|
|
||||||
|
# # 构造数组类型 (例如 int[cap])
|
||||||
|
# element_type = data_ptr.type.target()
|
||||||
|
# array_type = element_type.array(cap - 1) # C 数组声明语法
|
||||||
|
|
||||||
|
# return data_ptr.cast(array_type.pointer()).dereference()
|
||||||
|
|
||||||
|
# def to_string(self):
|
||||||
|
# if not self.check_vector_type():
|
||||||
|
# return "Not a vector type"
|
||||||
|
|
||||||
|
# size = self.val['size']
|
||||||
|
# cap = self.val['cap']
|
||||||
|
# data = self.get_array_view()
|
||||||
|
|
||||||
|
# return (f"vector(size={size}, cap={cap}, data={data})")
|
||||||
|
|
||||||
|
# class VectorInfoCommand(gdb.Command):
|
||||||
|
# """自定义命令:显示 vector 详细信息"""
|
||||||
|
|
||||||
|
# def __init__(self):
|
||||||
|
# super(VectorInfoCommand, self).__init__("vector_info",
|
||||||
|
# gdb.COMMAND_USER)
|
||||||
|
|
||||||
|
# def invoke(self, arg, from_tty):
|
||||||
|
# val = gdb.parse_and_eval(arg)
|
||||||
|
# printer = VectorPrinter(val)
|
||||||
|
|
||||||
|
# if not printer.check_vector_type():
|
||||||
|
# print(f"'{arg}' is not a vector structure")
|
||||||
|
# return
|
||||||
|
|
||||||
|
# size = int(val['size'])
|
||||||
|
# cap = int(val['cap'])
|
||||||
|
# data = printer.get_array_view()
|
||||||
|
|
||||||
|
# # 输出格式化信息
|
||||||
|
# print(f"Vector {arg}:")
|
||||||
|
# print(f"├─ Size: {size}")
|
||||||
|
# print(f"├─ Capacity: {cap}")
|
||||||
|
# print("└─ Data elements [0..{}]:".format(min(size, cap)-1))
|
||||||
|
|
||||||
|
# for i in range(min(size, cap)):
|
||||||
|
# try:
|
||||||
|
# print(f" [{i}]: {data[i]}")
|
||||||
|
# except gdb.MemoryError:
|
||||||
|
# print(f" [{i}]: <invalid memory>")
|
||||||
|
|
||||||
|
# def register_printers():
|
||||||
|
# """注册自动类型识别"""
|
||||||
|
# def vector_matcher(val):
|
||||||
|
# return VectorPrinter(val).check_vector_type()
|
||||||
|
|
||||||
|
# # 使用 lambda 包装以动态创建 printer
|
||||||
|
# gdb.pretty_printers.append(lambda val:
|
||||||
|
# VectorPrinter(val) if vector_matcher(val) else None)
|
||||||
|
|
||||||
|
# # 注册命令和打印机
|
||||||
|
# VectorInfoCommand()
|
||||||
|
# register_printers()
|
||||||
|
|
||||||
|
# vector_gdb.py
|
||||||
|
import gdb
|
||||||
|
from gdb.printing import PrettyPrinter
|
||||||
|
|
||||||
|
class VectorPrinter:
|
||||||
|
"""兼容新旧注册方式的最终方案"""
|
||||||
|
|
||||||
|
def __init__(self, val: gdb.Value):
|
||||||
|
self.val:gdb.Value = val
|
||||||
|
|
||||||
|
def check_type(self) -> bool:
|
||||||
|
"""类型检查(兼容匿名结构体)"""
|
||||||
|
try:
|
||||||
|
if self.val.type.code != gdb.TYPE_CODE_STRUCT:
|
||||||
|
return False
|
||||||
|
fields = self.val.type.fields()
|
||||||
|
if not fields:
|
||||||
|
return False
|
||||||
|
exp = ['size', 'cap', 'data']
|
||||||
|
for t in fields:
|
||||||
|
if t.name in exp:
|
||||||
|
exp.remove(t.name)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
except gdb.error:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if not self.check_type():
|
||||||
|
return "Not a vector"
|
||||||
|
|
||||||
|
return "vector({} size={}, cap={})".format(
|
||||||
|
self.val.address,
|
||||||
|
self.val['size'],
|
||||||
|
self.val['cap'],
|
||||||
|
)
|
||||||
|
|
||||||
|
def display_hint(self):
|
||||||
|
return 'array'
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
"""生成数组元素(关键改进点)"""
|
||||||
|
if not self.check_type():
|
||||||
|
return []
|
||||||
|
|
||||||
|
size = int(self.val['size'])
|
||||||
|
cap = int(self.val['cap'])
|
||||||
|
data_ptr = self.val['data']
|
||||||
|
|
||||||
|
if cap == 0 or data_ptr == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 使用 GDB 内置数组转换
|
||||||
|
array = data_ptr.dereference()
|
||||||
|
array = array.cast(data_ptr.type.target().array(cap - 1))
|
||||||
|
|
||||||
|
for i in range(size):
|
||||||
|
# state = "<used>" if i < size else "<unused>"
|
||||||
|
try:
|
||||||
|
value = array[i]
|
||||||
|
yield (f"[{i}] {value.type} {value.address}", value)
|
||||||
|
except gdb.MemoryError:
|
||||||
|
yield (f"[{i}]", "<invalid>")
|
||||||
|
|
||||||
|
# 注册方式一:传统append方法(您之前有效的方式)self
|
||||||
|
def append_printer():
|
||||||
|
gdb.pretty_printers.append(
|
||||||
|
lambda val: VectorPrinter(val) if VectorPrinter(val).check_type() else None
|
||||||
|
)
|
||||||
|
|
||||||
|
# 注册方式二:新版注册方法(备用方案)
|
||||||
|
def register_new_printer():
|
||||||
|
class VectorPrinterLocator(PrettyPrinter):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("vector_printer")
|
||||||
|
|
||||||
|
def __call__(self, val):
|
||||||
|
ret = VectorPrinter(val).check_type()
|
||||||
|
print(f"ret {ret}, type {val.type}, {[(i.name, i.type) for i in val.type.fields()]}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
gdb.printing.register_pretty_printer(
|
||||||
|
gdb.current_objfile(),
|
||||||
|
VectorPrinterLocator()
|
||||||
|
)
|
||||||
|
|
||||||
|
# 双重注册保证兼容性
|
||||||
|
append_printer() # 保留您原来有效的方式
|
||||||
|
# register_new_printer() # 添加新版注册
|
||||||
|
|
||||||
|
class VectorInfoCommand(gdb.Command):
|
||||||
|
"""保持原有命令不变"""
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("vector_info", gdb.COMMAND_USER)
|
||||||
|
|
||||||
|
def invoke(self, arg, from_tty):
|
||||||
|
val = gdb.parse_and_eval(arg)
|
||||||
|
printer = VectorPrinter(val)
|
||||||
|
|
||||||
|
if not printer.check_type():
|
||||||
|
print("Invalid vector")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("=== Vector Details ===")
|
||||||
|
print("Size:", val['size'])
|
||||||
|
print("Capacity:", val['cap'])
|
||||||
|
print("Elements:")
|
||||||
|
for name, value in printer.children():
|
||||||
|
print(f" {name}: {value}")
|
||||||
|
|
||||||
|
VectorInfoCommand()
|
54
libcore/vector.h
Normal file
54
libcore/vector.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// vector.h
|
||||||
|
#ifndef VECTOR_H
|
||||||
|
#define VECTOR_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define vector_header(name, type) \
|
||||||
|
struct { \
|
||||||
|
size_t size; \
|
||||||
|
size_t cap; \
|
||||||
|
type *data; \
|
||||||
|
} name \
|
||||||
|
|
||||||
|
#define vector_init(vec) \
|
||||||
|
do { \
|
||||||
|
(vec).size = 0, \
|
||||||
|
(vec).cap = 0, \
|
||||||
|
(vec).data = NULL; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define vector_push(vec, value) \
|
||||||
|
do { \
|
||||||
|
if (vec.size >= vec.cap) { \
|
||||||
|
int cap = vec.cap ? vec.cap * 2 : 8; \
|
||||||
|
void* data = realloc(vec.data, cap * sizeof(*vec.data)); \
|
||||||
|
if (!data) { \
|
||||||
|
fprintf(stderr, "vector_push: realloc failed\n"); \
|
||||||
|
exit(1); \
|
||||||
|
} \
|
||||||
|
(vec).cap = cap; \
|
||||||
|
(vec).data = data; \
|
||||||
|
} \
|
||||||
|
(vec).data[(vec).size++] = value; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define vector_pop(vec) \
|
||||||
|
((vec).data[--(vec).size])
|
||||||
|
|
||||||
|
#define vector_at(vec, idx) \
|
||||||
|
(((vec).data)[idx])
|
||||||
|
|
||||||
|
#define vector_idx(vec, ptr) \
|
||||||
|
((ptr) - (vec).data)
|
||||||
|
|
||||||
|
#define vector_free(vec) \
|
||||||
|
do { \
|
||||||
|
free((vec).data); \
|
||||||
|
(vec).data = NULL; \
|
||||||
|
(vec).size = (vec).cap = 0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user