feat(parser): 启用parser和ast模块并重构解析器结构
- 在cbuild.toml中启用parser和ast依赖项 - 将AST内置类型枚举重命名为SCC_AST_BUILTIN_TYPE_*前缀格式 - 修复ast_def.h中的类型字段命名,将builtin改为type - 添加逗号操作符支持到表达式操作符枚举中 - 更新字面量表达式的lexeme字段为const char*指针和owned标志 - 重构解析器头文件结构,分离为parser.h、parser_utils.h、scc_sema.h等 - 实现新的解析器工具函数,包括预览、消费、回溯等功能 - 更新声明解析逻辑,使用新的解析器接口进行token处理 - 添加符号表语义分析功能框架 - 修复词法分析器中token移动时的空指针检查 - 统一使用scc_tree_dump_printf替代直接的scc_printf调用
This commit is contained in:
@@ -6,8 +6,8 @@ dependencies = [
|
|||||||
{ name = "argparse", path = "./libs/argparse" },
|
{ name = "argparse", path = "./libs/argparse" },
|
||||||
{ name = "lexer", path = "./libs/lexer" },
|
{ name = "lexer", path = "./libs/lexer" },
|
||||||
{ name = "pproc", path = "./libs/pproc" },
|
{ name = "pproc", path = "./libs/pproc" },
|
||||||
# { name = "parser", path = "./libs/parser" },
|
{ name = "parser", path = "./libs/parser" },
|
||||||
# { name = "ast", path = "./libs/ast" },
|
{ name = "ast", path = "./libs/ast" },
|
||||||
# { name = "ast2ir", path = "./libs/ast2ir" },
|
# { name = "ast2ir", path = "./libs/ast2ir" },
|
||||||
# { name = "ir", path = "./libs/ir" },
|
# { name = "ir", path = "./libs/ir" },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -95,19 +95,19 @@ typedef struct {
|
|||||||
* @brief 内置类型枚举
|
* @brief 内置类型枚举
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TYPE_VOID,
|
SCC_AST_BUILTIN_TYPE_VOID,
|
||||||
TYPE_CHAR,
|
SCC_AST_BUILTIN_TYPE_CHAR,
|
||||||
TYPE_SHORT,
|
SCC_AST_BUILTIN_TYPE_SHORT,
|
||||||
TYPE_INT,
|
SCC_AST_BUILTIN_TYPE_INT,
|
||||||
TYPE_LONG,
|
SCC_AST_BUILTIN_TYPE_LONG,
|
||||||
TYPE_LONG_LONG,
|
SCC_AST_BUILTIN_TYPE_LONG_LONG,
|
||||||
TYPE_FLOAT,
|
SCC_AST_BUILTIN_TYPE_FLOAT,
|
||||||
TYPE_DOUBLE,
|
SCC_AST_BUILTIN_TYPE_DOUBLE,
|
||||||
TYPE_LONG_DOUBLE,
|
SCC_AST_BUILTIN_TYPE_LONG_DOUBLE,
|
||||||
TYPE_BOOL,
|
SCC_AST_BUILTIN_TYPE_BOOL,
|
||||||
TYPE_COMPLEX_FLOAT,
|
SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT,
|
||||||
TYPE_COMPLEX_DOUBLE,
|
SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE,
|
||||||
TYPE_COMPLEX_LONG_DOUBLE,
|
SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE,
|
||||||
} scc_ast_builtin_type_t;
|
} scc_ast_builtin_type_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,7 +150,7 @@ struct scc_ast_type {
|
|||||||
scc_ast_node_t base;
|
scc_ast_node_t base;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
scc_ast_builtin_type_t builtin;
|
scc_ast_builtin_type_t type;
|
||||||
scc_ast_decl_specifier_t quals;
|
scc_ast_decl_specifier_t quals;
|
||||||
} builtin;
|
} builtin;
|
||||||
struct {
|
struct {
|
||||||
@@ -188,7 +188,6 @@ struct scc_ast_type {
|
|||||||
typedef enum scc_ast_expr_op {
|
typedef enum scc_ast_expr_op {
|
||||||
/* 无操作符 */
|
/* 无操作符 */
|
||||||
SCC_AST_OP_NONE = 0,
|
SCC_AST_OP_NONE = 0,
|
||||||
|
|
||||||
/* 赋值操作符 */
|
/* 赋值操作符 */
|
||||||
SCC_AST_OP_ASSIGN, // =
|
SCC_AST_OP_ASSIGN, // =
|
||||||
SCC_AST_OP_ASSIGN_ADD, // +=
|
SCC_AST_OP_ASSIGN_ADD, // +=
|
||||||
@@ -201,40 +200,34 @@ typedef enum scc_ast_expr_op {
|
|||||||
SCC_AST_OP_ASSIGN_OR, // |=
|
SCC_AST_OP_ASSIGN_OR, // |=
|
||||||
SCC_AST_OP_ASSIGN_LSHIFT, // <<=
|
SCC_AST_OP_ASSIGN_LSHIFT, // <<=
|
||||||
SCC_AST_OP_ASSIGN_RSHIFT, // >>=
|
SCC_AST_OP_ASSIGN_RSHIFT, // >>=
|
||||||
|
|
||||||
/* 条件操作符 */
|
/* 条件操作符 */
|
||||||
SCC_AST_OP_CONDITIONAL, // ?:
|
SCC_AST_OP_CONDITIONAL, // ?:
|
||||||
|
/* 逗号操作符 */
|
||||||
|
SCC_AST_OP_COMMA, // ,
|
||||||
/* 逻辑操作符 */
|
/* 逻辑操作符 */
|
||||||
SCC_AST_OP_LOGICAL_OR, // ||
|
SCC_AST_OP_LOGICAL_OR, // ||
|
||||||
SCC_AST_OP_LOGICAL_AND, // &&
|
SCC_AST_OP_LOGICAL_AND, // &&
|
||||||
|
|
||||||
/* 位操作符 */
|
/* 位操作符 */
|
||||||
SCC_AST_OP_BITWISE_OR, // |
|
SCC_AST_OP_BITWISE_OR, // |
|
||||||
SCC_AST_OP_BITWISE_XOR, // ^
|
SCC_AST_OP_BITWISE_XOR, // ^
|
||||||
SCC_AST_OP_BITWISE_AND, // &
|
SCC_AST_OP_BITWISE_AND, // &
|
||||||
|
|
||||||
/* 相等性操作符 */
|
/* 相等性操作符 */
|
||||||
SCC_AST_OP_EQUAL, // ==
|
SCC_AST_OP_EQUAL, // ==
|
||||||
SCC_AST_OP_NOT_EQUAL, // !=
|
SCC_AST_OP_NOT_EQUAL, // !=
|
||||||
|
|
||||||
/* 关系操作符 */
|
/* 关系操作符 */
|
||||||
SCC_AST_OP_LESS, // <
|
SCC_AST_OP_LESS, // <
|
||||||
SCC_AST_OP_GREATER, // >
|
SCC_AST_OP_GREATER, // >
|
||||||
SCC_AST_OP_LESS_EQUAL, // <=
|
SCC_AST_OP_LESS_EQUAL, // <=
|
||||||
SCC_AST_OP_GREATER_EQUAL, // >=
|
SCC_AST_OP_GREATER_EQUAL, // >=
|
||||||
|
|
||||||
/* 移位操作符 */
|
/* 移位操作符 */
|
||||||
SCC_AST_OP_LEFT_SHIFT, // <<
|
SCC_AST_OP_LEFT_SHIFT, // <<
|
||||||
SCC_AST_OP_RIGHT_SHIFT, // >>
|
SCC_AST_OP_RIGHT_SHIFT, // >>
|
||||||
|
|
||||||
/* 算术操作符 */
|
/* 算术操作符 */
|
||||||
SCC_AST_OP_ADD, // +
|
SCC_AST_OP_ADD, // +
|
||||||
SCC_AST_OP_SUB, // -
|
SCC_AST_OP_SUB, // -
|
||||||
SCC_AST_OP_MUL, // *
|
SCC_AST_OP_MUL, // *
|
||||||
SCC_AST_OP_DIV, // /
|
SCC_AST_OP_DIV, // /
|
||||||
SCC_AST_OP_MOD, // %
|
SCC_AST_OP_MOD, // %
|
||||||
|
|
||||||
/* 一元操作符 */
|
/* 一元操作符 */
|
||||||
SCC_AST_OP_UNARY_PLUS, // + (一元)
|
SCC_AST_OP_UNARY_PLUS, // + (一元)
|
||||||
SCC_AST_OP_UNARY_MINUS, // - (一元)
|
SCC_AST_OP_UNARY_MINUS, // - (一元)
|
||||||
@@ -246,7 +239,6 @@ typedef enum scc_ast_expr_op {
|
|||||||
SCC_AST_OP_PREFIX_DECREMENT, // -- (前缀)
|
SCC_AST_OP_PREFIX_DECREMENT, // -- (前缀)
|
||||||
SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
|
SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
|
||||||
SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
|
SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
|
||||||
|
|
||||||
/* 成员访问 */
|
/* 成员访问 */
|
||||||
SCC_AST_OP_MEMBER_ACCESS, // .
|
SCC_AST_OP_MEMBER_ACCESS, // .
|
||||||
SCC_AST_OP_PTR_MEMBER_ACCESS, // ->
|
SCC_AST_OP_PTR_MEMBER_ACCESS, // ->
|
||||||
@@ -312,7 +304,8 @@ struct scc_ast_expr {
|
|||||||
} compound_literal;
|
} compound_literal;
|
||||||
// 字面量
|
// 字面量
|
||||||
struct {
|
struct {
|
||||||
scc_cstring_t lexme;
|
const char *lexme;
|
||||||
|
cbool owned;
|
||||||
} literal;
|
} literal;
|
||||||
// 标识符
|
// 标识符
|
||||||
struct {
|
struct {
|
||||||
@@ -408,7 +401,7 @@ struct scc_ast_decl {
|
|||||||
struct {
|
struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
scc_ast_type_t *type; // 函数类型
|
scc_ast_type_t *type; // 函数类型
|
||||||
scc_ast_stmt_t *body; // 可为 NULL(只有声明) or
|
scc_ast_stmt_t *body; // 可为 null 表示只有声明
|
||||||
} func;
|
} func;
|
||||||
// 参数声明
|
// 参数声明
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
#define __SCC_AST_H__
|
#define __SCC_AST_H__
|
||||||
|
|
||||||
#include "ast_def.h"
|
#include "ast_def.h"
|
||||||
|
#include "ast_dump.h"
|
||||||
|
|
||||||
#endif /* __SCC_AST_H__ */
|
#endif /* __SCC_AST_H__ */
|
||||||
|
|||||||
@@ -127,31 +127,31 @@ static const char *get_node_type_str(scc_ast_node_type_t type) {
|
|||||||
// 获取内置类型名称
|
// 获取内置类型名称
|
||||||
static const char *get_builtin_type_str(scc_ast_builtin_type_t type) {
|
static const char *get_builtin_type_str(scc_ast_builtin_type_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_VOID:
|
case SCC_AST_BUILTIN_TYPE_VOID:
|
||||||
return "void";
|
return "void";
|
||||||
case TYPE_CHAR:
|
case SCC_AST_BUILTIN_TYPE_CHAR:
|
||||||
return "char";
|
return "char";
|
||||||
case TYPE_SHORT:
|
case SCC_AST_BUILTIN_TYPE_SHORT:
|
||||||
return "short";
|
return "short";
|
||||||
case TYPE_INT:
|
case SCC_AST_BUILTIN_TYPE_INT:
|
||||||
return "int";
|
return "int";
|
||||||
case TYPE_LONG:
|
case SCC_AST_BUILTIN_TYPE_LONG:
|
||||||
return "long";
|
return "long";
|
||||||
case TYPE_LONG_LONG:
|
case SCC_AST_BUILTIN_TYPE_LONG_LONG:
|
||||||
return "long long";
|
return "long long";
|
||||||
case TYPE_FLOAT:
|
case SCC_AST_BUILTIN_TYPE_FLOAT:
|
||||||
return "float";
|
return "float";
|
||||||
case TYPE_DOUBLE:
|
case SCC_AST_BUILTIN_TYPE_DOUBLE:
|
||||||
return "double";
|
return "double";
|
||||||
case TYPE_LONG_DOUBLE:
|
case SCC_AST_BUILTIN_TYPE_LONG_DOUBLE:
|
||||||
return "long double";
|
return "long double";
|
||||||
case TYPE_BOOL:
|
case SCC_AST_BUILTIN_TYPE_BOOL:
|
||||||
return "_Bool";
|
return "_Bool";
|
||||||
case TYPE_COMPLEX_FLOAT:
|
case SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT:
|
||||||
return "float _Complex";
|
return "float _Complex";
|
||||||
case TYPE_COMPLEX_DOUBLE:
|
case SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE:
|
||||||
return "double _Complex";
|
return "double _Complex";
|
||||||
case TYPE_COMPLEX_LONG_DOUBLE:
|
case SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE:
|
||||||
return "long double _Complex";
|
return "long double _Complex";
|
||||||
default:
|
default:
|
||||||
return "<unknown>";
|
return "<unknown>";
|
||||||
@@ -259,7 +259,9 @@ static inline void start_node_dump(scc_ast_node_t *node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 通用的结束节点打印函数
|
// 通用的结束节点打印函数
|
||||||
static inline void end_node_dump(scc_tree_dump_ctx_t *ctx) { scc_printf("\n"); }
|
static inline void end_node_dump(scc_tree_dump_ctx_t *ctx) {
|
||||||
|
scc_tree_dump_printf(ctx, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
// 通用的递归转储辅助函数
|
// 通用的递归转储辅助函数
|
||||||
static inline void dump_child_node(scc_ast_node_t *child,
|
static inline void dump_child_node(scc_ast_node_t *child,
|
||||||
@@ -276,10 +278,11 @@ static inline void dump_child_node(scc_ast_node_t *child,
|
|||||||
#define BUILD_TYPE_NAME(ctx, prefix, name) \
|
#define BUILD_TYPE_NAME(ctx, prefix, name) \
|
||||||
do { \
|
do { \
|
||||||
if (ctx->use_color) { \
|
if (ctx->use_color) { \
|
||||||
scc_printf("%s'%s%s%s'%s", ctx->value_color, prefix, name, \
|
scc_tree_dump_printf(ctx, "%s'%s%s%s'%s", ctx->value_color, \
|
||||||
ctx->reset_color, ctx->reset_color); \
|
prefix, name, ctx->reset_color, \
|
||||||
|
ctx->reset_color); \
|
||||||
} else { \
|
} else { \
|
||||||
scc_printf("'%s%s'", prefix, name); \
|
scc_tree_dump_printf(ctx, "'%s%s'", prefix, name); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -293,18 +296,18 @@ static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_ctx_t *ctx) {
|
|||||||
// 根据类型输出特定信息
|
// 根据类型输出特定信息
|
||||||
switch (type->base.type) {
|
switch (type->base.type) {
|
||||||
case SCC_AST_TYPE_BUILTIN:
|
case SCC_AST_TYPE_BUILTIN:
|
||||||
PRINT_QUOTED_VALUE(ctx, get_builtin_type_str(type->builtin.builtin));
|
PRINT_QUOTED_VALUE(ctx, get_builtin_type_str(type->builtin.type));
|
||||||
break;
|
break;
|
||||||
case SCC_AST_TYPE_POINTER:
|
case SCC_AST_TYPE_POINTER:
|
||||||
if (type->pointer.pointee &&
|
if (type->pointer.pointee &&
|
||||||
type->pointer.pointee->base.type == SCC_AST_TYPE_BUILTIN) {
|
type->pointer.pointee->base.type == SCC_AST_TYPE_BUILTIN) {
|
||||||
const char *base_type =
|
const char *base_type =
|
||||||
get_builtin_type_str(type->pointer.pointee->builtin.builtin);
|
get_builtin_type_str(type->pointer.pointee->builtin.type);
|
||||||
if (ctx->use_color) {
|
if (ctx->use_color) {
|
||||||
scc_printf("%s'%s *'%s", ctx->value_color, base_type,
|
scc_tree_dump_printf(ctx, "%s'%s *'%s", ctx->value_color,
|
||||||
ctx->reset_color);
|
base_type, ctx->reset_color);
|
||||||
} else {
|
} else {
|
||||||
scc_printf("'%s *'", base_type);
|
scc_tree_dump_printf(ctx, "'%s *'", base_type);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PRINT_QUOTED_VALUE(ctx, "pointer");
|
PRINT_QUOTED_VALUE(ctx, "pointer");
|
||||||
@@ -315,7 +318,7 @@ static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_ctx_t *ctx) {
|
|||||||
break;
|
break;
|
||||||
case SCC_AST_TYPE_FUNCTION:
|
case SCC_AST_TYPE_FUNCTION:
|
||||||
PRINT_QUOTED_VALUE(ctx, "function");
|
PRINT_QUOTED_VALUE(ctx, "function");
|
||||||
scc_printf("\n");
|
scc_tree_dump_printf(ctx, "\n");
|
||||||
if (type->function.return_type) {
|
if (type->function.return_type) {
|
||||||
dump_type_impl(type->function.return_type, ctx);
|
dump_type_impl(type->function.return_type, ctx);
|
||||||
}
|
}
|
||||||
@@ -451,7 +454,7 @@ static void dump_expr_impl(scc_ast_expr_t *expr, scc_tree_dump_ctx_t *ctx) {
|
|||||||
// 打印成员访问信息
|
// 打印成员访问信息
|
||||||
scc_tree_print_indent(ctx);
|
scc_tree_print_indent(ctx);
|
||||||
PRINT_NODE(ctx, "Member [\"%s\"]", expr->member.member_name);
|
PRINT_NODE(ctx, "Member [\"%s\"]", expr->member.member_name);
|
||||||
scc_printf("\n");
|
scc_tree_dump_printf(ctx, "\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCC_AST_EXPR_CAST:
|
case SCC_AST_EXPR_CAST:
|
||||||
|
|||||||
0
libs/ast/src/scc_ast.c
Normal file
0
libs/ast/src/scc_ast.c
Normal file
@@ -146,8 +146,8 @@ typedef enum scc_cstd {
|
|||||||
// END
|
// END
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
typedef enum scc_tok_type {
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
typedef enum scc_tok_type {
|
||||||
// must first becase the unknown token must be 0
|
// must first becase the unknown token must be 0
|
||||||
#define X(str, subtype, tok) tok,
|
#define X(str, subtype, tok) tok,
|
||||||
SCC_CTOK_TABLE
|
SCC_CTOK_TABLE
|
||||||
@@ -160,8 +160,8 @@ typedef enum scc_tok_type {
|
|||||||
#define X(name, subtype, tok, std) tok,
|
#define X(name, subtype, tok, std) tok,
|
||||||
SCC_CKEYWORD_TABLE
|
SCC_CKEYWORD_TABLE
|
||||||
#undef X
|
#undef X
|
||||||
/* clang-format on*/
|
|
||||||
} scc_tok_type_t;
|
} scc_tok_type_t;
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
typedef enum scc_tok_subtype {
|
typedef enum scc_tok_subtype {
|
||||||
SCC_TOK_SUBTYPE_INVALID, // 错误占位
|
SCC_TOK_SUBTYPE_INVALID, // 错误占位
|
||||||
@@ -212,6 +212,7 @@ static inline scc_lexer_tok_t scc_lexer_tok_copy(const scc_lexer_tok_t *src) {
|
|||||||
// 移动 token(源 token 不再拥有 lexeme)
|
// 移动 token(源 token 不再拥有 lexeme)
|
||||||
static inline void scc_lexer_tok_move(scc_lexer_tok_t *dst,
|
static inline void scc_lexer_tok_move(scc_lexer_tok_t *dst,
|
||||||
scc_lexer_tok_t *src) {
|
scc_lexer_tok_t *src) {
|
||||||
|
Assert(src != null);
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
src->lexeme.data = null;
|
src->lexeme.data = null;
|
||||||
src->lexeme.size = 0;
|
src->lexeme.size = 0;
|
||||||
|
|||||||
@@ -474,8 +474,10 @@ void scc_lexer_get_valid_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
|
|||||||
if (subtype == SCC_TOK_SUBTYPE_EMPTYSPACE ||
|
if (subtype == SCC_TOK_SUBTYPE_EMPTYSPACE ||
|
||||||
subtype == SCC_TOK_SUBTYPE_COMMENT) {
|
subtype == SCC_TOK_SUBTYPE_COMMENT) {
|
||||||
scc_lexer_tok_drop(token);
|
scc_lexer_tok_drop(token);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file parser.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SCC_PARSER_H__
|
|
||||||
#define __SCC_PARSER_H__
|
|
||||||
|
|
||||||
#include "scc_ast.h"
|
|
||||||
#include <lexer.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 解析器状态
|
|
||||||
*/
|
|
||||||
typedef struct scc_parser {
|
|
||||||
scc_lexer_stream_t *lex_stream; // 词法分析器
|
|
||||||
scc_sema_callbacks_t sema_callbacks; // 语义分析回调
|
|
||||||
scc_ast_translation_unit_t *translation_unit; // 翻译单元(根节点)
|
|
||||||
cbool has_error; // 是否有错误
|
|
||||||
} scc_parser_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 检查当前 token 类型
|
|
||||||
*/
|
|
||||||
static inline cbool scc_parse_is(scc_lexer_stream_t *stream,
|
|
||||||
scc_tok_type_t type) {
|
|
||||||
const scc_lexer_tok_t *tok = scc_lexer_stream_current(stream);
|
|
||||||
return tok->type == type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 检查前瞻 token 类型
|
|
||||||
*/
|
|
||||||
static inline cbool scc_parse_peek_is(scc_lexer_stream_t *stream, usize n,
|
|
||||||
scc_tok_type_t type) {
|
|
||||||
const scc_lexer_tok_t *tok = scc_lexer_stream_peek(stream, n);
|
|
||||||
return tok->type == type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 如果当前 token 匹配则消费
|
|
||||||
*/
|
|
||||||
static inline cbool scc_parse_consume_if(scc_lexer_stream_t *stream,
|
|
||||||
scc_tok_type_t type) {
|
|
||||||
if (scc_parse_is(stream, type)) {
|
|
||||||
scc_lexer_stream_consume(stream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 消费当前 token 并返回它
|
|
||||||
*/
|
|
||||||
static inline const scc_lexer_tok_t *
|
|
||||||
scc_parse_consume(scc_lexer_stream_t *stream) {
|
|
||||||
const scc_lexer_tok_t *tok = scc_lexer_stream_current(stream);
|
|
||||||
scc_lexer_stream_consume(stream);
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化解析器
|
|
||||||
* @param parser 解析器实例
|
|
||||||
* @param lexer 词法分析器实例
|
|
||||||
* @param callbacks 语义分析回调(可为 null)
|
|
||||||
*/
|
|
||||||
void scc_parser_init(scc_parser_t *parser, scc_lexer_stream_t *lexer,
|
|
||||||
scc_sema_callbacks_t *callbacks);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 销毁解析器
|
|
||||||
* @param parser 解析器实例
|
|
||||||
*/
|
|
||||||
void scc_parser_drop(scc_parser_t *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 解析整个翻译单元
|
|
||||||
* @param parser 解析器实例
|
|
||||||
* @return 翻译单元 AST 节点
|
|
||||||
*/
|
|
||||||
scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 解析声明
|
|
||||||
* @param parser 解析器实例
|
|
||||||
* @return 声明 AST 节点
|
|
||||||
*/
|
|
||||||
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 解析语句
|
|
||||||
* @param parser 解析器实例
|
|
||||||
* @return 语句 AST 节点
|
|
||||||
*/
|
|
||||||
scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 解析表达式
|
|
||||||
* @param parser 解析器实例
|
|
||||||
* @return 表达式 AST 节点
|
|
||||||
*/
|
|
||||||
scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 解析类型
|
|
||||||
* @param parser 解析器实例
|
|
||||||
* @return 类型 AST 节点
|
|
||||||
*/
|
|
||||||
scc_ast_type_t *scc_parse_type(scc_parser_t *parser);
|
|
||||||
|
|
||||||
cbool scc_parse_is_declaration_start(scc_parser_t *parser, usize offset);
|
|
||||||
|
|
||||||
#endif /* __SCC_PARSER_H__ */
|
|
||||||
69
libs/parser/include/parser_utils.h
Normal file
69
libs/parser/include/parser_utils.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#ifndef __SCC_PARSER_UTILS_H__
|
||||||
|
#define __SCC_PARSER_UTILS_H__
|
||||||
|
|
||||||
|
#include "scc_parser.h"
|
||||||
|
|
||||||
|
static inline const scc_lexer_tok_t *scc_parser_peek(scc_parser_t *parser) {
|
||||||
|
cbool ok = false;
|
||||||
|
const scc_lexer_tok_t *tok = null;
|
||||||
|
scc_ring_unsafe_peek_ref(*parser->ring, tok, ok);
|
||||||
|
if (ok == false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const scc_lexer_tok_t *scc_parser_next(scc_parser_t *parser) {
|
||||||
|
cbool ok = false;
|
||||||
|
const scc_lexer_tok_t *tok = null;
|
||||||
|
scc_ring_unsafe_next_ref(*parser->ring, tok, ok);
|
||||||
|
if (ok == false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline cbool scc_parser_consume_if(scc_parser_t *parser,
|
||||||
|
scc_tok_type_t type) {
|
||||||
|
cbool ok = false;
|
||||||
|
scc_lexer_tok_t *tok = null;
|
||||||
|
scc_ring_unsafe_peek_ref(*parser->ring, tok, ok);
|
||||||
|
if (ok == false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (tok->type == type) {
|
||||||
|
scc_lexer_tok_drop(tok);
|
||||||
|
scc_ring_unsafe_pure_next_consume(*parser->ring);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void scc_parser_store(scc_parser_t *parser) {
|
||||||
|
parser->checkpoint = _scc_ring_probe(*parser->ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void scc_parser_restore(scc_parser_t *parser) {
|
||||||
|
_scc_ring_probe(*parser->ring) = parser->checkpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline cbool scc_parser_next_consume(scc_parser_t *parser,
|
||||||
|
scc_lexer_tok_t *tok) {
|
||||||
|
cbool ok = false;
|
||||||
|
scc_lexer_tok_t *raw_tok_ref = null;
|
||||||
|
scc_ring_unsafe_next_ref_consume(*parser->ring, raw_tok_ref, ok);
|
||||||
|
scc_lexer_tok_move(tok, raw_tok_ref);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void scc_parser_commit(scc_parser_t *parser) {
|
||||||
|
// Memory leak
|
||||||
|
scc_ring_consume(*parser->ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void scc_parser_reset(scc_parser_t *parser) {
|
||||||
|
scc_ring_reset(*parser->ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SCC_PARSER_UTILS_H__ */
|
||||||
75
libs/parser/include/scc_parser.h
Normal file
75
libs/parser/include/scc_parser.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef __SCC_PARSER_H__
|
||||||
|
#define __SCC_PARSER_H__
|
||||||
|
|
||||||
|
#include "scc_sema.h"
|
||||||
|
#include <scc_ast.h>
|
||||||
|
#include <scc_core_ring.h>
|
||||||
|
#include <scc_lexer_token.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析器状态
|
||||||
|
*/
|
||||||
|
typedef struct scc_parser {
|
||||||
|
scc_lexer_tok_ring_t *ring;
|
||||||
|
usize checkpoint;
|
||||||
|
|
||||||
|
scc_sema_callbacks_t sema_callbacks;
|
||||||
|
scc_ast_translation_unit_t *translation_unit;
|
||||||
|
int errcode;
|
||||||
|
} scc_parser_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化解析器
|
||||||
|
* @param parser 解析器实例
|
||||||
|
* @param lexer 词法分析器实例
|
||||||
|
* @param callbacks 语义分析回调(可为 null)
|
||||||
|
*/
|
||||||
|
void scc_parser_init(scc_parser_t *parser, scc_lexer_tok_ring_t *tok_ring,
|
||||||
|
scc_sema_callbacks_t *callbacks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 销毁解析器
|
||||||
|
* @param parser 解析器实例
|
||||||
|
*/
|
||||||
|
void scc_parser_drop(scc_parser_t *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析整个翻译单元
|
||||||
|
* @param parser 解析器实例
|
||||||
|
* @return 翻译单元 AST 节点
|
||||||
|
*/
|
||||||
|
scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析声明
|
||||||
|
* @param parser 解析器实例
|
||||||
|
* @return 声明 AST 节点
|
||||||
|
*/
|
||||||
|
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析语句
|
||||||
|
* @param parser 解析器实例
|
||||||
|
* @return 语句 AST 节点
|
||||||
|
*/
|
||||||
|
scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析表达式
|
||||||
|
* @param parser 解析器实例
|
||||||
|
* @return 表达式 AST 节点
|
||||||
|
*/
|
||||||
|
scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解析类型
|
||||||
|
* @param parser 解析器实例
|
||||||
|
* @return 类型 AST 节点
|
||||||
|
*/
|
||||||
|
scc_ast_type_t *scc_parse_type(scc_parser_t *parser);
|
||||||
|
|
||||||
|
static inline scc_ast_type_t *scc_parse_type_name(scc_parser_t *parser) {
|
||||||
|
return null; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SCC_PARSER_H__ */
|
||||||
25
libs/parser/include/scc_sema.h
Normal file
25
libs/parser/include/scc_sema.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __SCC_SEMA_H__
|
||||||
|
#define __SCC_SEMA_H__
|
||||||
|
|
||||||
|
#include <scc_ast.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 语义分析回调函数类型
|
||||||
|
*/
|
||||||
|
typedef void (*scc_sema_callback_t)(void *context,
|
||||||
|
scc_ast_node_type_t node_type, void *node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 语义分析回调集合
|
||||||
|
*/
|
||||||
|
typedef struct scc_sema_callbacks {
|
||||||
|
scc_sema_callback_t on_decl;
|
||||||
|
scc_sema_callback_t on_stmt;
|
||||||
|
scc_sema_callback_t on_expr;
|
||||||
|
scc_sema_callback_t on_type;
|
||||||
|
void *context;
|
||||||
|
} scc_sema_callbacks_t;
|
||||||
|
|
||||||
|
void scc_sema_init(scc_sema_callbacks_t *callbacks);
|
||||||
|
|
||||||
|
#endif /* __SCC_SEMA_H__ */
|
||||||
28
libs/parser/include/sema_symtab.h
Normal file
28
libs/parser/include/sema_symtab.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef __SCC_SEMA_SYMTAB_H__
|
||||||
|
#define __SCC_SEMA_SYMTAB_H__
|
||||||
|
|
||||||
|
#include <scc_ast.h>
|
||||||
|
#include <scc_utils.h>
|
||||||
|
|
||||||
|
typedef struct scc_parser_scope {
|
||||||
|
scc_hashtable_t symbols;
|
||||||
|
struct scc_parser_scope *parent;
|
||||||
|
} scc_sema_scope_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
scc_sema_scope_t root_scope;
|
||||||
|
scc_sema_scope_t *current_scope;
|
||||||
|
} scc_sema_symtab_t;
|
||||||
|
|
||||||
|
void scc_sema_symtab_init(scc_sema_symtab_t *symtab);
|
||||||
|
void scc_sema_symtab_drop(scc_sema_symtab_t *symtab);
|
||||||
|
|
||||||
|
void scc_sema_symtab_enter_scope(scc_sema_symtab_t *symtab);
|
||||||
|
void scc_sema_symtab_leave_scope(scc_sema_symtab_t *symtab);
|
||||||
|
scc_ast_node_t *scc_sema_symtab_add_symbol(scc_sema_symtab_t *symtab,
|
||||||
|
const char *name,
|
||||||
|
scc_ast_node_t *ast_node_ref);
|
||||||
|
scc_ast_node_t *scc_sema_symtab_lookup_symbol(scc_sema_symtab_t *symtab,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
#endif /* __SCC_SEMA_SYMTAB_H__ */
|
||||||
@@ -1,156 +1,159 @@
|
|||||||
#include <parser.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A.2.2 Declarations
|
A.2.2 Declarations
|
||||||
(6.7) declaration:
|
|
||||||
declaration-specifiers init-declarator-list(opt) ;
|
(6.7) declaration:
|
||||||
(6.7) declaration-specifiers:
|
declaration-specifiers init-declarator-list(opt) ;
|
||||||
storage-class-specifier declaration-specifiers(opt)
|
(6.7) declaration-specifiers:
|
||||||
type-specifier declaration-specifiers(opt)
|
storage-class-specifier declaration-specifiers(opt)
|
||||||
type-qualifier declaration-specifiers(opt)
|
type-specifier declaration-specifiers(opt)
|
||||||
function-specifier declaration-specifiers(opt)
|
type-qualifier declaration-specifiers(opt)
|
||||||
(6.7) init-declarator-list:
|
function-specifier declaration-specifiers(opt)
|
||||||
init-declarator
|
(6.7) init-declarator-list:
|
||||||
init-declarator-list , init-declarator
|
init-declarator
|
||||||
(6.7) init-declarator:
|
init-declarator-list , init-declarator
|
||||||
declarator
|
(6.7) init-declarator:
|
||||||
declarator = initializer
|
declarator
|
||||||
(6.7.1) storage-class-specifier:
|
declarator = initializer
|
||||||
typedef
|
(6.7.1) storage-class-specifier:
|
||||||
extern
|
typedef
|
||||||
static
|
extern
|
||||||
auto
|
static
|
||||||
register
|
auto
|
||||||
(6.7.2) type-specifier:
|
register
|
||||||
void
|
(6.7.2) type-specifier:
|
||||||
char
|
void
|
||||||
short
|
char
|
||||||
int
|
short
|
||||||
long
|
int
|
||||||
float
|
long
|
||||||
double
|
float
|
||||||
signed
|
double
|
||||||
unsigned
|
signed
|
||||||
_Bool
|
unsigned
|
||||||
_Complex
|
_Bool
|
||||||
struct-or-union-specifier
|
_Complex
|
||||||
enum-specifier
|
struct-or-union-specifier
|
||||||
typedef-name
|
enum-specifier
|
||||||
(6.7.2.1) struct-or-union-specifier:
|
typedef-name
|
||||||
struct-or-union identifier(opt) { struct-declaration-list }
|
(6.7.2.1) struct-or-union-specifier:
|
||||||
struct-or-union identifier
|
struct-or-union identifier(opt) { struct-declaration-list }
|
||||||
(6.7.2.1) struct-or-union:
|
struct-or-union identifier
|
||||||
struct
|
(6.7.2.1) struct-or-union:
|
||||||
union
|
struct
|
||||||
(6.7.2.1) struct-declaration-list:
|
union
|
||||||
struct-declaration
|
(6.7.2.1) struct-declaration-list:
|
||||||
struct-declaration-list struct-declaration
|
struct-declaration
|
||||||
(6.7.2.1) struct-declaration:
|
struct-declaration-list struct-declaration
|
||||||
specifier-qualifier-list struct-declarator-list ;
|
(6.7.2.1) struct-declaration:
|
||||||
(6.7.2.1) specifier-qualifier-list:
|
specifier-qualifier-list struct-declarator-list ;
|
||||||
type-specifier specifier-qualifier-list(opt)
|
(6.7.2.1) specifier-qualifier-list:
|
||||||
type-qualifier specifier-qualifier-list(opt)
|
type-specifier specifier-qualifier-list(opt)
|
||||||
(6.7.2.1) struct-declarator-list:
|
type-qualifier specifier-qualifier-list(opt)
|
||||||
struct-declarator
|
(6.7.2.1) struct-declarator-list:
|
||||||
struct-declarator-list , struct-declarator
|
struct-declarator
|
||||||
(6.7.2.1) struct-declarator:
|
struct-declarator-list , struct-declarator
|
||||||
declarator
|
(6.7.2.1) struct-declarator:
|
||||||
declarator(opt) : constant-expression
|
declarator
|
||||||
(6.7.2.2) enum-specifier:
|
declarator(opt) : constant-expression
|
||||||
enum identifier(opt) { enumerator-list }
|
(6.7.2.2) enum-specifier:
|
||||||
enum identifier(opt) { enumerator-list ,}
|
enum identifier(opt) { enumerator-list }
|
||||||
enum identifier
|
enum identifier(opt) { enumerator-list ,}
|
||||||
(6.7.2.2) enumerator-list:
|
enum identifier
|
||||||
enumerator
|
(6.7.2.2) enumerator-list:
|
||||||
enumerator-list , enumerator
|
enumerator
|
||||||
(6.7.2.2) enumerator:
|
enumerator-list , enumerator
|
||||||
enumeration-constant
|
(6.7.2.2) enumerator:
|
||||||
enumeration-constant = constant-expression
|
enumeration-constant
|
||||||
(6.7.3) type-qualifier:
|
enumeration-constant = constant-expression
|
||||||
const
|
(6.7.3) type-qualifier:
|
||||||
restrict
|
const
|
||||||
volatile
|
restrict
|
||||||
(6.7.4) function-specifier:
|
volatile
|
||||||
inline
|
(6.7.4) function-specifier:
|
||||||
(6.7.5) declarator:
|
inline
|
||||||
pointer(opt) direct-declarator
|
(6.7.5) declarator:
|
||||||
(6.7.5) direct-declarator:
|
pointer(opt) direct-declarator
|
||||||
identifier
|
(6.7.5) direct-declarator:
|
||||||
( declarator )
|
identifier
|
||||||
direct-declarator [ type-qualifier-list(opt)
|
( declarator )
|
||||||
assignment-expression(opt) ]
|
direct-declarator [ type-qualifier-list(opt)
|
||||||
direct-declarator [ static type-qualifier-list(opt)
|
assignment-expression(opt) ]
|
||||||
assignment-expression ]
|
direct-declarator [ static type-qualifier-list(opt)
|
||||||
direct-declarator [ type-qualifier-list static
|
assignment-expression ]
|
||||||
assignment-expression ]
|
direct-declarator [ type-qualifier-list static
|
||||||
direct-declarator [ type-qualifier-list(opt) *]
|
assignment-expression ]
|
||||||
direct-declarator ( parameter-type-list )
|
direct-declarator [ type-qualifier-list(opt) *]
|
||||||
direct-declarator ( identifier-list(opt) )
|
direct-declarator ( parameter-type-list )
|
||||||
(6.7.5) pointer:
|
direct-declarator ( identifier-list(opt) )
|
||||||
* type-qualifier-list(opt)
|
(6.7.5) pointer:
|
||||||
* type-qualifier-list(opt) pointer
|
* type-qualifier-list(opt)
|
||||||
(6.7.5) type-qualifier-list:
|
* type-qualifier-list(opt) pointer
|
||||||
type-qualifier
|
(6.7.5) type-qualifier-list:
|
||||||
type-qualifier-list type-qualifier
|
type-qualifier
|
||||||
(6.7.5) parameter-type-list:
|
type-qualifier-list type-qualifier
|
||||||
parameter-list
|
(6.7.5) parameter-type-list:
|
||||||
parameter-list , ...
|
parameter-list
|
||||||
(6.7.5) parameter-list:
|
parameter-list , ...
|
||||||
parameter-declaration
|
(6.7.5) parameter-list:
|
||||||
parameter-list , parameter-declaration
|
parameter-declaration
|
||||||
(6.7.5) parameter-declaration:
|
parameter-list , parameter-declaration
|
||||||
declaration-specifiers declarator
|
(6.7.5) parameter-declaration:
|
||||||
declaration-specifiers abstract-declarator(opt)
|
declaration-specifiers declarator
|
||||||
(6.7.5) identifier-list:
|
declaration-specifiers abstract-declarator(opt)
|
||||||
identifier
|
(6.7.5) identifier-list:
|
||||||
identifier-list , identifier
|
identifier
|
||||||
(6.7.6) type-name:
|
identifier-list , identifier
|
||||||
specifier-qualifier-list abstract-declarator(opt)
|
(6.7.6) type-name:
|
||||||
(6.7.6) abstract-declarator:
|
specifier-qualifier-list abstract-declarator(opt)
|
||||||
pointer
|
(6.7.6) abstract-declarator:
|
||||||
pointer(opt) direct-abstract-declarator
|
pointer
|
||||||
(6.7.6) direct-abstract-declarator:
|
pointer(opt) direct-abstract-declarator
|
||||||
( abstract-declarator )
|
(6.7.6) direct-abstract-declarator:
|
||||||
direct-abstract-declarator(opt) [ type-qualifier-list (opt)
|
( abstract-declarator )
|
||||||
assignment-expression(opt) ]
|
direct-abstract-declarator(opt) [ type-qualifier-list (opt)
|
||||||
direct-abstract-declarator(opt) [static type-qualifier-list(opt)
|
assignment-expression(opt) ]
|
||||||
assignment-expression ]
|
direct-abstract-declarator(opt) [static type-qualifier-list(opt)
|
||||||
direct-abstract-declaratoropt [ type-qualifier-list static
|
assignment-expression ]
|
||||||
assignment-expression ]
|
direct-abstract-declaratoropt [ type-qualifier-list static
|
||||||
direct-abstract-declarator(opt) [ * ]
|
assignment-expression ]
|
||||||
direct-abstract-declarator(opt) ( parameter-type-list(opt) )
|
direct-abstract-declarator(opt) [ * ]
|
||||||
(6.7.7) typedef-name:
|
direct-abstract-declarator(opt) ( parameter-type-list(opt) )
|
||||||
identifier
|
(6.7.7) typedef-name:
|
||||||
(6.7.8) initializer:
|
identifier
|
||||||
assignment-expression
|
(6.7.8) initializer:
|
||||||
{ initializer-list }
|
assignment-expression
|
||||||
{ initializer-list , }
|
{ initializer-list }
|
||||||
(6.7.8) initializer-list:
|
{ initializer-list , }
|
||||||
designation(opt) initializer
|
(6.7.8) initializer-list:
|
||||||
initializer-list , designation(opt) initializer
|
designation(opt) initializer
|
||||||
(6.7.8) designation:
|
initializer-list , designation(opt) initializer
|
||||||
designator-list =
|
(6.7.8) designation:
|
||||||
(6.7.8) designator-list:
|
designator-list =
|
||||||
designator
|
(6.7.8) designator-list:
|
||||||
designator-list designator
|
designator
|
||||||
(6.7.8) designator:
|
designator-list designator
|
||||||
[ constant-expression ]
|
(6.7.8) designator:
|
||||||
. identifier
|
[ constant-expression ]
|
||||||
|
. identifier
|
||||||
|
|
||||||
A.2.4 External definitions
|
A.2.4 External definitions
|
||||||
(6.9) translation-unit:
|
|
||||||
external-declaration
|
(6.9) translation-unit:
|
||||||
translation-unit external-declaration
|
external-declaration
|
||||||
(6.9) external-declaration:
|
translation-unit external-declaration
|
||||||
function-definition
|
(6.9) external-declaration:
|
||||||
declaration
|
function-definition
|
||||||
(6.9.1) function-definition:
|
declaration
|
||||||
declaration-specifiers declarator declaration-list(opt)
|
(6.9.1) function-definition:
|
||||||
compound-statement
|
declaration-specifiers declarator declaration-listopt compound-statement
|
||||||
(6.9.1) declaration-list:
|
(6.9.1) declaration-list:
|
||||||
declaration
|
declaration
|
||||||
declaration-list declaration
|
declaration-list declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <parser_utils.h>
|
||||||
|
#include <scc_parser.h>
|
||||||
|
|
||||||
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||||
/**
|
/**
|
||||||
* ISO/IEC 9899:TC3
|
* ISO/IEC 9899:TC3
|
||||||
@@ -171,22 +174,36 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
|||||||
* declarator
|
* declarator
|
||||||
* declarator = initializer
|
* declarator = initializer
|
||||||
*/
|
*/
|
||||||
if (!scc_parse_is_declaration_start(parser, 0)) {
|
cbool ok;
|
||||||
|
const scc_lexer_tok_t *tok_ptr = scc_parser_next(parser);
|
||||||
|
scc_lexer_tok_t tok;
|
||||||
|
if (tok_ptr == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
scc_ast_type_t *type = scc_parse_type(parser);
|
|
||||||
|
scc_ast_type_t *type = scc_malloc(sizeof(scc_ast_type_t));
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
LOG_ERROR("Failed to parse type");
|
LOG_FATAL("out of memory");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scc_lexer_tok_t *tok = scc_lexer_stream_current(parser->lex_stream);
|
if (tok_ptr->type != SCC_TOK_INT) {
|
||||||
if (!scc_lexer_tok_match(tok, SCC_TOK_IDENT)) {
|
// TODO back it
|
||||||
LOG_ERROR("Expected identifier, got %s", scc_get_tok_name(tok->type));
|
scc_parser_reset(parser);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
type->base.type = SCC_AST_TYPE_BUILTIN;
|
||||||
|
type->base.loc = tok_ptr->loc;
|
||||||
|
type->builtin.type = SCC_AST_BUILTIN_TYPE_INT;
|
||||||
|
type->builtin.quals = (scc_ast_decl_specifier_t){0};
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_parser_commit(parser);
|
||||||
|
ok = scc_parser_next_consume(parser, &tok);
|
||||||
|
if (ok == false) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_lexer_stream_consume(parser->lex_stream);
|
|
||||||
scc_ast_decl_t *decl = scc_malloc(sizeof(scc_ast_decl_t));
|
scc_ast_decl_t *decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -202,27 +219,28 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
|||||||
direct-declarator ( parameter-type-list )
|
direct-declarator ( parameter-type-list )
|
||||||
direct-declarator ( identifier-listopt )
|
direct-declarator ( identifier-listopt )
|
||||||
*/
|
*/
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_L_PAREN)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) {
|
||||||
// TODO
|
// TODO
|
||||||
if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_SEMICOLON)) {
|
if (scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||||
decl->base.type = SCC_AST_DECL_VAR;
|
decl->base.type = SCC_AST_DECL_VAR;
|
||||||
decl->var.type = type;
|
decl->var.type = type;
|
||||||
decl->var.name = tok->value.cstr.data;
|
decl->var.name = scc_cstring_as_cstr(&tok.lexeme);
|
||||||
decl->var.init = null;
|
decl->var.init = null;
|
||||||
return decl;
|
goto RETURN;
|
||||||
} else if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_ASSIGN)) {
|
} else if (scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) {
|
||||||
decl->base.type = SCC_AST_DECL_VAR;
|
decl->base.type = SCC_AST_DECL_VAR;
|
||||||
decl->var.type = type;
|
decl->var.type = type;
|
||||||
decl->var.name = tok->value.cstr.data;
|
decl->var.name = scc_cstring_as_cstr(&tok.lexeme);
|
||||||
decl->var.init = scc_parse_expression(parser);
|
decl->var.init = null; // scc_parse_expression(parser);
|
||||||
return decl;
|
goto RETURN;
|
||||||
}
|
}
|
||||||
|
// TODO
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function decl
|
// function decl
|
||||||
decl->base.type = SCC_AST_DECL_FUNC;
|
decl->base.type = SCC_AST_DECL_FUNC;
|
||||||
decl->func.name = tok->value.cstr.data;
|
decl->func.name = scc_cstring_as_cstr(&tok.lexeme);
|
||||||
decl->func.type = scc_malloc(sizeof(scc_ast_type_t));
|
decl->func.type = scc_malloc(sizeof(scc_ast_type_t));
|
||||||
decl->func.type->base.type = SCC_AST_TYPE_FUNCTION;
|
decl->func.type->base.type = SCC_AST_TYPE_FUNCTION;
|
||||||
scc_vec_init(decl->func.type->function.param_types);
|
scc_vec_init(decl->func.type->function.param_types);
|
||||||
@@ -231,20 +249,32 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
|||||||
decl->func.type->function.is_variadic = false;
|
decl->func.type->function.is_variadic = false;
|
||||||
|
|
||||||
// TODO param type
|
// TODO param type
|
||||||
scc_parse_consume_if(parser->lex_stream, SCC_TOK_VOID);
|
scc_parser_consume_if(parser, SCC_TOK_VOID);
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_R_PAREN)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scc_parse_is(parser->lex_stream, SCC_TOK_L_BRACE)) {
|
tok_ptr = scc_parser_peek(parser);
|
||||||
|
if (tok_ptr == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (tok_ptr->type != SCC_TOK_L_BRACE) {
|
||||||
|
if (tok_ptr->type == SCC_TOK_SEMICOLON) {
|
||||||
|
decl->func.body = null;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decl->func.body = scc_parse_statement(parser);
|
decl->func.body = scc_parse_statement(parser);
|
||||||
Assert(decl->func.type != null);
|
Assert(decl->func.type != null);
|
||||||
Assert(decl->func.type->base.type == SCC_AST_TYPE_FUNCTION);
|
Assert(decl->func.type->base.type == SCC_AST_TYPE_FUNCTION);
|
||||||
Assert(decl->func.body != null);
|
Assert(decl->func.body != null);
|
||||||
Assert(decl->func.body->base.type == SCC_AST_STMT_COMPOUND);
|
Assert(decl->func.body->base.type == SCC_AST_STMT_COMPOUND);
|
||||||
|
|
||||||
|
RETURN:
|
||||||
|
parser->sema_callbacks.on_decl(parser->sema_callbacks.context,
|
||||||
|
decl->base.type, decl);
|
||||||
return decl;
|
return decl;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
415
|
|
||||||
ISO/IEC 9899:TC3
|
|
||||||
Committee Draft — Septermber 7, 2007
|
|
||||||
WG14/N1256
|
|
||||||
|
|
||||||
A.2.3 Statements
|
A.2.3 Statements
|
||||||
|
|
||||||
(6.8)
|
(6.8)
|
||||||
statement:
|
statement:
|
||||||
labeled-statement
|
labeled-statement
|
||||||
@@ -50,37 +46,37 @@ A.2.3 Statements
|
|||||||
break ;
|
break ;
|
||||||
return expression(opt) ;
|
return expression(opt) ;
|
||||||
*/
|
*/
|
||||||
#include <parser.h>
|
|
||||||
|
|
||||||
|
#include <parser_utils.h>
|
||||||
|
#include <scc_parser.h>
|
||||||
static inline scc_ast_stmt_t *ast_stmt_alloc() {
|
static inline scc_ast_stmt_t *ast_stmt_alloc() {
|
||||||
scc_ast_stmt_t *stmt = (scc_ast_stmt_t *)scc_malloc(sizeof(scc_ast_stmt_t));
|
scc_ast_stmt_t *stmt = (scc_ast_stmt_t *)scc_malloc(sizeof(scc_ast_stmt_t));
|
||||||
Assert(stmt != null);
|
Assert(stmt != null);
|
||||||
stmt->base.type = SCC_AST_TRANSLATION_UNIT;
|
stmt->base.type = SCC_AST_UNKNOWN;
|
||||||
stmt->base.loc = scc_pos_create();
|
stmt->base.loc = scc_pos_create();
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline scc_ast_expr_t *ast_parse_paren_expression(scc_parser_t *parser) {
|
static inline scc_ast_expr_t *ast_parse_paren_expression(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_L_PAREN)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) {
|
||||||
LOG_ERROR("Expected '(' before like `( expression )` .");
|
LOG_ERROR("Expected '(' before like `( expression )` .");
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_ast_expr_t *ret = scc_parse_expression(parser);
|
scc_ast_expr_t *ret = scc_parse_expression(parser);
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_R_PAREN)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||||
LOG_ERROR("Expected ')' after like `( expression )` .");
|
LOG_ERROR("Expected ')' before like `( expression )` .");
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser) {
|
||||||
const scc_lexer_tok_t *tok = scc_lexer_stream_current(parser->lex_stream);
|
scc_lexer_tok_t tok = {0};
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_IDENT)) {
|
if (!scc_parser_next_consume(parser, &tok)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_COLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_COLON)) {
|
||||||
LOG_ERROR("Expected constant expression after case.");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,21 +89,20 @@ static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser) {
|
|||||||
Assert(stmt != null);
|
Assert(stmt != null);
|
||||||
|
|
||||||
stmt->base.type = SCC_AST_STMT_LABEL;
|
stmt->base.type = SCC_AST_STMT_LABEL;
|
||||||
// TODO maybe use cstring
|
stmt->label_stmt.label = scc_cstring_as_cstr(&tok.lexeme);
|
||||||
stmt->label_stmt.label = tok->value.cstr.data;
|
|
||||||
stmt->label_stmt.stmt = statement;
|
stmt->label_stmt.stmt = statement;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_CASE)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_CASE)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_ast_expr_t *expr = null;
|
scc_ast_expr_t *expr = null;
|
||||||
// TODO = scc_parser_constant_expression();
|
// TODO = scc_parser_constant_expression();
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_COLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_COLON)) {
|
||||||
LOG_ERROR("Expected constant expression after case.");
|
LOG_ERROR("Expected constant expression after case.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -126,11 +121,11 @@ static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_DEFAULT)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_DEFAULT)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_COLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_COLON)) {
|
||||||
LOG_ERROR("Expected constant expression after case.");
|
LOG_ERROR("Expected constant expression after case.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -148,14 +143,14 @@ static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_L_BRACE)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_L_BRACE)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||||
stmt->base.type = SCC_AST_STMT_COMPOUND;
|
stmt->base.type = SCC_AST_STMT_COMPOUND;
|
||||||
|
|
||||||
scc_vec_init(stmt->compound.block_items);
|
scc_vec_init(stmt->compound.block_items);
|
||||||
while (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_R_BRACE)) {
|
while (!scc_parser_consume_if(parser, SCC_TOK_R_BRACE)) {
|
||||||
/// TODO
|
/// TODO
|
||||||
// scc_parse_is_decl();
|
// scc_parse_is_decl();
|
||||||
scc_ast_node_t *ret = null;
|
scc_ast_node_t *ret = null;
|
||||||
@@ -175,7 +170,7 @@ static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_IF)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_IF)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +181,7 @@ static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser) {
|
|||||||
stmt->base.type = SCC_AST_STMT_IF;
|
stmt->base.type = SCC_AST_STMT_IF;
|
||||||
stmt->if_stmt.cond = expression;
|
stmt->if_stmt.cond = expression;
|
||||||
stmt->if_stmt.then_stmt = statement;
|
stmt->if_stmt.then_stmt = statement;
|
||||||
if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_ELSE)) {
|
if (scc_parser_consume_if(parser, SCC_TOK_ELSE)) {
|
||||||
stmt->if_stmt.opt_else_stmt = scc_parse_statement(parser);
|
stmt->if_stmt.opt_else_stmt = scc_parse_statement(parser);
|
||||||
} else {
|
} else {
|
||||||
stmt->if_stmt.opt_else_stmt = null;
|
stmt->if_stmt.opt_else_stmt = null;
|
||||||
@@ -195,7 +190,7 @@ static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_SWITCH)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_SWITCH)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +205,7 @@ static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_WHILE)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_WHILE)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,13 +220,13 @@ static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_DO)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_DO)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_ast_stmt_t *statement = scc_parse_statement(parser);
|
scc_ast_stmt_t *statement = scc_parse_statement(parser);
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_WHILE)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_WHILE)) {
|
||||||
LOG_ERROR("Expected 'while' after do.");
|
LOG_ERROR("Expected 'while' after do.");
|
||||||
// TODO 使用更好的错误处理,未来应当采用更好的内存管理器
|
// TODO 使用更好的错误处理,未来应当采用更好的内存管理器
|
||||||
scc_free(statement);
|
scc_free(statement);
|
||||||
@@ -247,7 +242,7 @@ static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_FOR)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_FOR)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +251,7 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
|||||||
for ( declaration expression(opt) ; expression(opt) ) statement
|
for ( declaration expression(opt) ; expression(opt) ) statement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_L_PAREN)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) {
|
||||||
LOG_ERROR("Expected '(' before like `( expression )` .");
|
LOG_ERROR("Expected '(' before like `( expression )` .");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,19 +261,19 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
|||||||
// TODO use decl or expr
|
// TODO use decl or expr
|
||||||
stmt->for_stmt.init = (scc_ast_type_t *)scc_parse_expression(parser);
|
stmt->for_stmt.init = (scc_ast_type_t *)scc_parse_expression(parser);
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_SEMICOLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||||
LOG_ERROR("Expected semicolon in for statement.");
|
LOG_ERROR("Expected semicolon in for statement.");
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt->for_stmt.cond = scc_parse_expression(parser);
|
stmt->for_stmt.cond = scc_parse_expression(parser);
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_SEMICOLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||||
LOG_ERROR("Expected semicolon in for statement.");
|
LOG_ERROR("Expected semicolon in for statement.");
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt->for_stmt.iter = scc_parse_expression(parser);
|
stmt->for_stmt.iter = scc_parse_expression(parser);
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_R_PAREN)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||||
LOG_ERROR("Expected ')' after like `( expression )` .");
|
LOG_ERROR("Expected ')' after like `( expression )` .");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,28 +285,26 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
|||||||
static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser) {
|
static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser) {
|
||||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||||
|
|
||||||
if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_GOTO)) {
|
if (scc_parser_consume_if(parser, SCC_TOK_GOTO)) {
|
||||||
stmt->base.type = SCC_AST_STMT_GOTO;
|
stmt->base.type = SCC_AST_STMT_GOTO;
|
||||||
if (scc_parse_is(parser->lex_stream, SCC_TOK_IDENT)) {
|
scc_lexer_tok_t tok = {0};
|
||||||
const scc_lexer_tok_t *tok =
|
if (scc_parser_next_consume(parser, &tok)) {
|
||||||
scc_lexer_stream_current(parser->lex_stream);
|
stmt->goto_stmt.label = scc_cstring_as_cstr(&tok.lexeme);
|
||||||
stmt->goto_stmt.label = tok->value.cstr.data;
|
|
||||||
scc_lexer_stream_consume(parser->lex_stream);
|
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Expected label after goto.");
|
LOG_ERROR("Expected label after goto.");
|
||||||
}
|
}
|
||||||
} else if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_CONTINUE)) {
|
} else if (scc_parser_consume_if(parser, SCC_TOK_CONTINUE)) {
|
||||||
stmt->base.type = SCC_AST_STMT_CONTINUE;
|
stmt->base.type = SCC_AST_STMT_CONTINUE;
|
||||||
} else if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_BREAK)) {
|
} else if (scc_parser_consume_if(parser, SCC_TOK_BREAK)) {
|
||||||
stmt->base.type = SCC_AST_STMT_BREAK;
|
stmt->base.type = SCC_AST_STMT_BREAK;
|
||||||
} else if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_RETURN)) {
|
} else if (scc_parser_consume_if(parser, SCC_TOK_RETURN)) {
|
||||||
stmt->base.type = SCC_AST_STMT_RETURN;
|
stmt->base.type = SCC_AST_STMT_RETURN;
|
||||||
stmt->return_stmt.expr = scc_parse_expression(parser);
|
stmt->return_stmt.expr = scc_parse_expression(parser);
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_SEMICOLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||||
LOG_ERROR("Expected semicolon after jump statement.");
|
LOG_ERROR("Expected semicolon after jump statement.");
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
@@ -321,7 +314,7 @@ static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser) {
|
|||||||
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
scc_ast_stmt_t *stmt = ast_stmt_alloc();
|
||||||
stmt->base.type = SCC_AST_STMT_EXPR;
|
stmt->base.type = SCC_AST_STMT_EXPR;
|
||||||
|
|
||||||
if (scc_parse_consume_if(parser->lex_stream, SCC_TOK_SEMICOLON)) {
|
if (scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||||
stmt->expr.expr = null;
|
stmt->expr.expr = null;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
@@ -333,15 +326,20 @@ static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scc_parse_consume_if(parser->lex_stream, SCC_TOK_SEMICOLON)) {
|
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||||
LOG_ERROR("Expected semicolon after expression.");
|
LOG_ERROR("Expected semicolon after expression.");
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
||||||
const scc_lexer_tok_t *tok = scc_lexer_stream_current(parser->lex_stream);
|
scc_ast_stmt_t *stmt;
|
||||||
switch (tok->type) {
|
const scc_lexer_tok_t *tok_ref;
|
||||||
|
tok_ref = scc_parser_peek(parser);
|
||||||
|
if (!tok_ref) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (tok_ref->type) {
|
||||||
/*
|
/*
|
||||||
(6.8.1)
|
(6.8.1)
|
||||||
labeled-statement:
|
labeled-statement:
|
||||||
@@ -350,15 +348,19 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
|||||||
default : statement
|
default : statement
|
||||||
*/
|
*/
|
||||||
case SCC_TOK_IDENT:
|
case SCC_TOK_IDENT:
|
||||||
// 注意需要检测下一个 token 是否为冒号,否则将需要判定成表达式语句
|
tok_ref = scc_parser_next(parser);
|
||||||
if (!scc_parse_peek_is(parser->lex_stream, 1, SCC_TOK_COLON)) {
|
if (tok_ref == null || tok_ref->type != SCC_TOK_COLON) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return parse_label_statement(parser);
|
stmt = parse_label_statement(parser);
|
||||||
case SCC_TOK_CASE:
|
goto RETURN;
|
||||||
return parse_case_statement(parser);
|
case SCC_TOK_CASE: {
|
||||||
|
stmt = parse_case_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
case SCC_TOK_DEFAULT:
|
case SCC_TOK_DEFAULT:
|
||||||
return parse_default_statement(parser);
|
stmt = parse_default_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
/*
|
/*
|
||||||
(6.8.2)
|
(6.8.2)
|
||||||
compound-statement:
|
compound-statement:
|
||||||
@@ -373,7 +375,8 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
|||||||
statement
|
statement
|
||||||
*/
|
*/
|
||||||
case SCC_TOK_L_BRACE:
|
case SCC_TOK_L_BRACE:
|
||||||
return parse_compound_statement(parser);
|
stmt = parse_compound_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
/*
|
/*
|
||||||
(6.8.4)
|
(6.8.4)
|
||||||
selection-statement:
|
selection-statement:
|
||||||
@@ -382,9 +385,11 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
|||||||
switch ( expression ) statement
|
switch ( expression ) statement
|
||||||
*/
|
*/
|
||||||
case SCC_TOK_IF:
|
case SCC_TOK_IF:
|
||||||
return parse_if_statement(parser);
|
stmt = parse_if_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
case SCC_TOK_SWITCH:
|
case SCC_TOK_SWITCH:
|
||||||
return parse_switch_statement(parser);
|
stmt = parse_switch_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
/*
|
/*
|
||||||
(6.8.5)
|
(6.8.5)
|
||||||
iteration-statement:
|
iteration-statement:
|
||||||
@@ -396,11 +401,14 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
|||||||
statement
|
statement
|
||||||
*/
|
*/
|
||||||
case SCC_TOK_WHILE:
|
case SCC_TOK_WHILE:
|
||||||
return parse_while_statement(parser);
|
stmt = parse_while_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
case SCC_TOK_DO:
|
case SCC_TOK_DO:
|
||||||
return parse_do_while_statement(parser);
|
stmt = parse_do_while_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
case SCC_TOK_FOR:
|
case SCC_TOK_FOR:
|
||||||
return parse_for_statement(parser);
|
stmt = parse_for_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
/*
|
/*
|
||||||
(6.8.6)
|
(6.8.6)
|
||||||
jump-statement:
|
jump-statement:
|
||||||
@@ -413,7 +421,8 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
|||||||
case SCC_TOK_CONTINUE:
|
case SCC_TOK_CONTINUE:
|
||||||
case SCC_TOK_BREAK:
|
case SCC_TOK_BREAK:
|
||||||
case SCC_TOK_RETURN:
|
case SCC_TOK_RETURN:
|
||||||
return parse_jump_statement(parser);
|
stmt = parse_jump_statement(parser);
|
||||||
|
goto RETURN;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -422,5 +431,10 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) {
|
|||||||
expression-statement:
|
expression-statement:
|
||||||
expression(opt) ;
|
expression(opt) ;
|
||||||
*/
|
*/
|
||||||
return parse_expression_statement(parser);
|
stmt = parse_expression_statement(parser);
|
||||||
|
RETURN:
|
||||||
|
scc_parser_reset(parser);
|
||||||
|
parser->sema_callbacks.on_stmt(parser->sema_callbacks.context,
|
||||||
|
stmt->base.type, stmt);
|
||||||
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,5 @@
|
|||||||
/**
|
#include <parser_utils.h>
|
||||||
* @file parser.c
|
#include <scc_parser.h>
|
||||||
* @brief 新的解析器实现
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "parser.h"
|
|
||||||
#include <log.h>
|
|
||||||
|
|
||||||
static void dummy_sema_callback(void *context, scc_ast_node_type_t node_type,
|
static void dummy_sema_callback(void *context, scc_ast_node_type_t node_type,
|
||||||
void *node) {
|
void *node) {
|
||||||
(void)context;
|
(void)context;
|
||||||
@@ -17,11 +11,11 @@ static void dummy_sema_callback(void *context, scc_ast_node_type_t node_type,
|
|||||||
#define ASSIGN_PTR_OR_DEFAULT(assigned_val, value, default) \
|
#define ASSIGN_PTR_OR_DEFAULT(assigned_val, value, default) \
|
||||||
assigned_val = value ? value : default
|
assigned_val = value ? value : default
|
||||||
|
|
||||||
void scc_parser_init(scc_parser_t *parser, scc_lexer_stream_t *lexer,
|
void scc_parser_init(scc_parser_t *parser, scc_lexer_tok_ring_t *tok_ring,
|
||||||
scc_sema_callbacks_t *callbacks) {
|
scc_sema_callbacks_t *callbacks) {
|
||||||
Assert(parser != null && lexer != null);
|
Assert(parser != null && tok_ring != null);
|
||||||
parser->lex_stream = lexer;
|
parser->ring = tok_ring;
|
||||||
parser->has_error = false;
|
parser->errcode = 0;
|
||||||
parser->translation_unit = null;
|
parser->translation_unit = null;
|
||||||
if (callbacks) {
|
if (callbacks) {
|
||||||
ASSIGN_PTR_OR_DEFAULT(parser->sema_callbacks.on_decl,
|
ASSIGN_PTR_OR_DEFAULT(parser->sema_callbacks.on_decl,
|
||||||
@@ -38,15 +32,12 @@ void scc_parser_init(scc_parser_t *parser, scc_lexer_stream_t *lexer,
|
|||||||
parser->sema_callbacks.on_stmt = dummy_sema_callback;
|
parser->sema_callbacks.on_stmt = dummy_sema_callback;
|
||||||
parser->sema_callbacks.on_expr = dummy_sema_callback;
|
parser->sema_callbacks.on_expr = dummy_sema_callback;
|
||||||
parser->sema_callbacks.on_type = dummy_sema_callback;
|
parser->sema_callbacks.on_type = dummy_sema_callback;
|
||||||
parser->sema_callbacks.context = dummy_sema_callback;
|
parser->sema_callbacks.context = null;
|
||||||
}
|
}
|
||||||
// // ONLY FOR INIT TYPE
|
|
||||||
// parser->current_token.type = SCC_TOK_UNKNOWN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_parser_drop(scc_parser_t *parser) {
|
void scc_parser_drop(scc_parser_t *parser) {
|
||||||
// TODO: 释放 AST 内存
|
// TODO: 释放 AST 内存
|
||||||
(void)parser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
||||||
@@ -62,7 +53,8 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
|||||||
* same as
|
* same as
|
||||||
* Program := Declaration* Definition*
|
* Program := Declaration* Definition*
|
||||||
*/
|
*/
|
||||||
do {
|
cbool matched = false;
|
||||||
|
while (1) {
|
||||||
scc_ast_decl_t *decl = scc_parse_declaration(parser);
|
scc_ast_decl_t *decl = scc_parse_declaration(parser);
|
||||||
if (decl != null) {
|
if (decl != null) {
|
||||||
scc_vec_push(unit->declarations, decl);
|
scc_vec_push(unit->declarations, decl);
|
||||||
@@ -70,11 +62,16 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
|||||||
break;
|
break;
|
||||||
// MAYBE return or next
|
// MAYBE return or next
|
||||||
}
|
}
|
||||||
} while (!scc_lexer_tok_match(scc_lexer_stream_current(parser->lex_stream),
|
if (parser->errcode != 0) { // FIXME errcode
|
||||||
SCC_TOK_EOF) &&
|
break;
|
||||||
!parser->has_error);
|
}
|
||||||
|
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||||
|
if (tok == null || tok->type == SCC_TOK_EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (parser->has_error) {
|
if (parser->errcode) {
|
||||||
// TODO: 清理
|
// TODO: 清理
|
||||||
scc_free(unit);
|
scc_free(unit);
|
||||||
return null;
|
return null;
|
||||||
15
libs/parser/src/scc_sema.c
Normal file
15
libs/parser/src/scc_sema.c
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include <scc_sema.h>
|
||||||
|
#include <sema_symtab.h>
|
||||||
|
|
||||||
|
void scc_sema_init(scc_sema_callbacks_t *callbacks) {
|
||||||
|
scc_sema_symtab_t *sema_symtab = scc_malloc(sizeof(scc_sema_symtab_t));
|
||||||
|
if (sema_symtab == null) {
|
||||||
|
LOG_FATAL("out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callbacks->context = sema_symtab;
|
||||||
|
callbacks->on_decl = null;
|
||||||
|
callbacks->on_expr = null;
|
||||||
|
callbacks->on_stmt = null;
|
||||||
|
callbacks->on_type = null;
|
||||||
|
}
|
||||||
58
libs/parser/src/sema_symtab.c
Normal file
58
libs/parser/src/sema_symtab.c
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include <sema_symtab.h>
|
||||||
|
|
||||||
|
void scc_sema_symtab_init(scc_sema_symtab_t *symtab) {
|
||||||
|
symtab->root_scope.parent = null;
|
||||||
|
|
||||||
|
scc_hashtable_init(&symtab->root_scope.symbols,
|
||||||
|
(scc_hashtable_hash_func_t)scc_strcmp,
|
||||||
|
(scc_hashtable_equal_func_t)scc_strhash32);
|
||||||
|
symtab->current_scope = &symtab->root_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_sema_symtab_drop(scc_sema_symtab_t *symtab) {
|
||||||
|
while (symtab->current_scope != null) {
|
||||||
|
scc_hashtable_drop(&symtab->current_scope->symbols);
|
||||||
|
symtab->current_scope = symtab->current_scope->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_sema_symtab_enter_scope(scc_sema_symtab_t *symtab) {
|
||||||
|
scc_sema_scope_t *scope = scc_malloc(sizeof(scc_sema_scope_t));
|
||||||
|
if (scope == null) {
|
||||||
|
LOG_FATAL("out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scope->parent = symtab->current_scope;
|
||||||
|
scc_hashtable_init(&scope->symbols, (scc_hashtable_hash_func_t)scc_strcmp,
|
||||||
|
(scc_hashtable_equal_func_t)scc_strhash32);
|
||||||
|
symtab->current_scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_sema_symtab_leave_scope(scc_sema_symtab_t *symtab) {
|
||||||
|
if (symtab->current_scope == &symtab->root_scope) {
|
||||||
|
LOG_ERROR("out of scope");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scc_hashtable_drop(&symtab->current_scope->symbols);
|
||||||
|
symtab->current_scope = symtab->current_scope->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_ast_node_t *scc_sema_symtab_add_symbol(scc_sema_symtab_t *symtab,
|
||||||
|
const char *name,
|
||||||
|
scc_ast_node_t *ast_node_ref) {
|
||||||
|
return scc_hashtable_set(&symtab->current_scope->symbols, name,
|
||||||
|
ast_node_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
scc_ast_node_t *scc_sema_symtab_lookup_symbol(scc_sema_symtab_t *symtab,
|
||||||
|
const char *name) {
|
||||||
|
scc_ast_node_t *node = null;
|
||||||
|
for (scc_sema_scope_t *scope = symtab->current_scope; scope != null;
|
||||||
|
scope = scope->parent) {
|
||||||
|
node = scc_hashtable_get(&scope->symbols, name);
|
||||||
|
if (node != null) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
453
libs/parser/tests/test_parser_unit.c
Normal file
453
libs/parser/tests/test_parser_unit.c
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <scc_lexer.h>
|
||||||
|
#include <scc_parser.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <utest/acutest.h>
|
||||||
|
|
||||||
|
typedef scc_ast_node_t *(*scc_parse_node_func)(scc_parser_t *parser);
|
||||||
|
|
||||||
|
static scc_ast_node_t *process_input(const char *input,
|
||||||
|
scc_parse_node_func parse_func) {
|
||||||
|
int res = 0;
|
||||||
|
scc_sstream_t mem_stream;
|
||||||
|
res = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
|
||||||
|
16);
|
||||||
|
Assert(res == 0);
|
||||||
|
|
||||||
|
scc_lexer_t lexer;
|
||||||
|
scc_lexer_init(&lexer, scc_sstream_to_ring(&mem_stream));
|
||||||
|
|
||||||
|
scc_lexer_tok_ring_t *tok_ring = scc_lexer_to_ring(&lexer, 8, false);
|
||||||
|
|
||||||
|
scc_parser_t parser;
|
||||||
|
scc_parser_init(&parser, tok_ring, null);
|
||||||
|
|
||||||
|
scc_ast_node_t *ret = parse_func(&parser);
|
||||||
|
|
||||||
|
cbool not_eof = false;
|
||||||
|
scc_ring_not_eof(*parser.ring, not_eof);
|
||||||
|
Assert(!not_eof == true);
|
||||||
|
|
||||||
|
scc_lexer_drop_ring(parser.ring);
|
||||||
|
scc_parser_drop(&parser);
|
||||||
|
scc_lexer_drop(&lexer);
|
||||||
|
scc_sstream_drop(&mem_stream);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*scc_tree_dump_output_t)(void *userdata, const char *fmt, ...);
|
||||||
|
|
||||||
|
#define BUFFER_SIZE (4096)
|
||||||
|
char expect_buffer[BUFFER_SIZE];
|
||||||
|
char output_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
static void dump2buffer(void *_buffer, const char *fmt, ...) {
|
||||||
|
char *buffer = _buffer;
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
scc_vsnprintf(buffer + strlen(buffer), BUFFER_SIZE - strlen(buffer) - 1,
|
||||||
|
fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCC_CHECK_AST(expect_node_ptr, str, parse_func) \
|
||||||
|
do { \
|
||||||
|
scc_ast_node_t *output_node_ptr = \
|
||||||
|
process_input(str, (scc_parse_node_func)parse_func); \
|
||||||
|
scc_tree_dump_ctx_t ctx; \
|
||||||
|
expect_buffer[0] = '\n', expect_buffer[1] = '\0'; \
|
||||||
|
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer); \
|
||||||
|
scc_ast_dump_node(&ctx, expect_node_ptr); \
|
||||||
|
scc_tree_dump_ctx_drop(&ctx); \
|
||||||
|
output_buffer[0] = '\n', output_buffer[1] = '\0'; \
|
||||||
|
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, output_buffer); \
|
||||||
|
scc_ast_dump_node(&ctx, output_node_ptr); \
|
||||||
|
scc_tree_dump_ctx_drop(&ctx); \
|
||||||
|
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
|
||||||
|
TEST_MSG("Expected: %s", expect_buffer); \
|
||||||
|
TEST_MSG("Produced: %s", output_buffer); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
static void test_parser_unit(void) {
|
||||||
|
scc_ast_decl_t int_decl = {
|
||||||
|
.base.type = SCC_AST_DECL_VAR,
|
||||||
|
.var.name = "a",
|
||||||
|
.var.init = null,
|
||||||
|
.var.type = &(scc_ast_type_t){.base.type = SCC_AST_TYPE_BUILTIN,
|
||||||
|
.builtin.type = SCC_AST_BUILTIN_TYPE_INT},
|
||||||
|
};
|
||||||
|
SCC_CHECK_AST(&int_decl.base, "int a;", scc_parse_declaration);
|
||||||
|
|
||||||
|
scc_ast_decl_t func_decl = {
|
||||||
|
.base.type = SCC_AST_DECL_FUNC,
|
||||||
|
.func.name = "main",
|
||||||
|
.func.body =
|
||||||
|
&(scc_ast_stmt_t){
|
||||||
|
.base.type = SCC_AST_STMT_COMPOUND,
|
||||||
|
.compound.block_items = {0},
|
||||||
|
},
|
||||||
|
.func.type =
|
||||||
|
&(scc_ast_type_t){
|
||||||
|
.base.type = SCC_AST_TYPE_FUNCTION,
|
||||||
|
.function.is_variadic = false,
|
||||||
|
.function.param_types = {0},
|
||||||
|
.function.return_type =
|
||||||
|
&(scc_ast_type_t){.base.type = SCC_AST_TYPE_BUILTIN,
|
||||||
|
.builtin.type = SCC_AST_BUILTIN_TYPE_INT},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
SCC_CHECK_AST(&func_decl.base, "int main(void) {}", scc_parse_declaration);
|
||||||
|
|
||||||
|
scc_ast_decl_t *decls[] = {&func_decl};
|
||||||
|
scc_ast_translation_unit_t tu = {
|
||||||
|
.base.type = SCC_AST_TRANSLATION_UNIT,
|
||||||
|
.declarations.data = decls,
|
||||||
|
.declarations.cap = 1,
|
||||||
|
.declarations.size = 1,
|
||||||
|
};
|
||||||
|
SCC_CHECK_AST(&tu.base, "int main(void) {}", scc_parse_translation_unit);
|
||||||
|
// SCC_CHECK_AST(&func_decl.base, "int main(void);", scc_parse_declaration);
|
||||||
|
|
||||||
|
{
|
||||||
|
scc_ast_node_t *items[] = {
|
||||||
|
(scc_ast_node_t *)&(scc_ast_stmt_t){
|
||||||
|
.base.type = SCC_AST_STMT_RETURN,
|
||||||
|
.return_stmt.expr =
|
||||||
|
&(scc_ast_expr_t){
|
||||||
|
.base.type = SCC_AST_EXPR_INT_LITERAL,
|
||||||
|
.literal.lexme = "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
scc_ast_decl_t func_decl = {
|
||||||
|
.base.type = SCC_AST_DECL_FUNC,
|
||||||
|
.func.name = "main",
|
||||||
|
.func.body =
|
||||||
|
&(scc_ast_stmt_t){
|
||||||
|
.base.type = SCC_AST_STMT_COMPOUND,
|
||||||
|
.compound.block_items.cap = 1,
|
||||||
|
.compound.block_items.size = 1,
|
||||||
|
.compound.block_items.data = items,
|
||||||
|
},
|
||||||
|
.func.type =
|
||||||
|
&(scc_ast_type_t){
|
||||||
|
.base.type = SCC_AST_TYPE_FUNCTION,
|
||||||
|
.function.is_variadic = false,
|
||||||
|
.function.param_types = {0},
|
||||||
|
.function.return_type =
|
||||||
|
&(scc_ast_type_t){.base.type = SCC_AST_TYPE_BUILTIN,
|
||||||
|
.builtin.type =
|
||||||
|
SCC_AST_BUILTIN_TYPE_INT},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
scc_ast_decl_t *decls[] = {&func_decl};
|
||||||
|
scc_ast_translation_unit_t tu = {
|
||||||
|
.base.type = SCC_AST_TRANSLATION_UNIT,
|
||||||
|
.declarations.cap = 1,
|
||||||
|
.declarations.size = 1,
|
||||||
|
.declarations.data = decls,
|
||||||
|
};
|
||||||
|
SCC_CHECK_AST(&tu.base, "int main(void) { return 0; }",
|
||||||
|
scc_parse_translation_unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_binary(scc_ast_expr_op_t op, scc_ast_expr_t *lhs,
|
||||||
|
scc_ast_expr_t *rhs) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_BINARY};
|
||||||
|
expr.binary.op = op;
|
||||||
|
expr.binary.lhs = lhs;
|
||||||
|
expr.binary.rhs = rhs;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_unary(scc_ast_expr_op_t op,
|
||||||
|
scc_ast_expr_t *operand) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_UNARY};
|
||||||
|
expr.unary.op = op;
|
||||||
|
expr.unary.operand = operand;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_identifier(char *name) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_IDENTIFIER};
|
||||||
|
expr.identifier.name = name;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_int_literal(char *val) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_INT_LITERAL};
|
||||||
|
expr.literal.lexme = val;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_float_literal(char *val) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_FLOAT_LITERAL};
|
||||||
|
expr.literal.lexme = val;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_string_literal(char *val) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_STRING_LITERAL};
|
||||||
|
expr.literal.lexme = val;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_char_literal(char *val) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_CHAR_LITERAL};
|
||||||
|
expr.literal.lexme = val;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_conditional(scc_ast_expr_t *cond,
|
||||||
|
scc_ast_expr_t *then_expr,
|
||||||
|
scc_ast_expr_t *else_expr) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_COND};
|
||||||
|
expr.cond.cond = cond;
|
||||||
|
expr.cond.then_expr = then_expr;
|
||||||
|
expr.cond.else_expr = else_expr;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scc_ast_expr_t make_call(scc_ast_expr_t *callee,
|
||||||
|
scc_ast_expr_vec_t *args) {
|
||||||
|
scc_ast_expr_t expr = {.base.type = SCC_AST_EXPR_CALL};
|
||||||
|
expr.call.callee = callee;
|
||||||
|
// 注意:args 需要提前初始化,此处简化处理,实际测试中可能需要动态分配
|
||||||
|
// 我们将在具体测试中手动初始化 args 数组
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_parser_expression(void) {
|
||||||
|
// 1. 基本表达式:标识符、整数常量、字符串字面量、括号
|
||||||
|
{
|
||||||
|
scc_ast_expr_t ident = make_identifier("x");
|
||||||
|
SCC_CHECK_AST(&ident.base, "x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t int_lit = make_int_literal("42");
|
||||||
|
SCC_CHECK_AST(&int_lit.base, "42", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t str_lit = make_string_literal("\"hello\"");
|
||||||
|
SCC_CHECK_AST(&str_lit.base, "\"hello\"", scc_parse_expression);
|
||||||
|
|
||||||
|
// 括号表达式
|
||||||
|
scc_ast_expr_t paren_ident = make_identifier("y");
|
||||||
|
SCC_CHECK_AST(&paren_ident.base, "(y)", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 后缀表达式
|
||||||
|
{
|
||||||
|
// 数组下标:a[10]
|
||||||
|
scc_ast_expr_t a = make_identifier("a");
|
||||||
|
scc_ast_expr_t index = make_int_literal("10");
|
||||||
|
scc_ast_expr_t subscript = {.base.type = SCC_AST_EXPR_ARRAY_SUBSCRIPT};
|
||||||
|
subscript.subscript.array = &a;
|
||||||
|
subscript.subscript.index = &index;
|
||||||
|
SCC_CHECK_AST(&subscript.base, "a[10]", scc_parse_expression);
|
||||||
|
|
||||||
|
// 函数调用:f()
|
||||||
|
scc_ast_expr_t f = make_identifier("f");
|
||||||
|
scc_ast_expr_t call = {.base.type = SCC_AST_EXPR_CALL};
|
||||||
|
call.call.callee = &f;
|
||||||
|
scc_ast_expr_vec_t args;
|
||||||
|
scc_vec_init(args);
|
||||||
|
call.call.args = args; // 空参数列表
|
||||||
|
SCC_CHECK_AST(&call.base, "f()", scc_parse_expression);
|
||||||
|
|
||||||
|
// 函数调用带参数:f(1, x)
|
||||||
|
scc_ast_expr_t f2 = make_identifier("f");
|
||||||
|
scc_ast_expr_t arg1 = make_int_literal("1");
|
||||||
|
scc_ast_expr_t arg2 = make_identifier("x");
|
||||||
|
scc_ast_expr_vec_t args2;
|
||||||
|
scc_vec_init(args2);
|
||||||
|
scc_vec_push(args2, &arg1);
|
||||||
|
scc_vec_push(args2, &arg2);
|
||||||
|
scc_ast_expr_t call2 = {.base.type = SCC_AST_EXPR_CALL};
|
||||||
|
call2.call.callee = &f2;
|
||||||
|
call2.call.args = args2;
|
||||||
|
SCC_CHECK_AST(&call2.base, "f(1, x)", scc_parse_expression);
|
||||||
|
|
||||||
|
// 成员访问 . 和 ->
|
||||||
|
scc_ast_expr_t s = make_identifier("s");
|
||||||
|
scc_ast_expr_t dot = {.base.type = SCC_AST_EXPR_MEMBER};
|
||||||
|
dot.member.base = &s;
|
||||||
|
dot.member.member_name = "field";
|
||||||
|
SCC_CHECK_AST(&dot.base, "s.field", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t p = make_identifier("p");
|
||||||
|
scc_ast_expr_t arrow = {.base.type = SCC_AST_EXPR_PTR_MEMBER};
|
||||||
|
arrow.ptr_member.base = &p;
|
||||||
|
arrow.ptr_member.member_name = "field";
|
||||||
|
SCC_CHECK_AST(&arrow.base, "p->field", scc_parse_expression);
|
||||||
|
|
||||||
|
// 后缀 ++/--
|
||||||
|
scc_ast_expr_t x = make_identifier("x");
|
||||||
|
scc_ast_expr_t post_inc = make_unary(SCC_AST_OP_POSTFIX_INCREMENT, &x);
|
||||||
|
SCC_CHECK_AST(&post_inc.base, "x++", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t post_dec = make_unary(SCC_AST_OP_POSTFIX_DECREMENT, &x);
|
||||||
|
SCC_CHECK_AST(&post_dec.base, "x--", scc_parse_expression);
|
||||||
|
|
||||||
|
// 复合字面量 TODO: (int){1,2} 需要更复杂的构造,暂略
|
||||||
|
// SCC_CHECK_AST(..., "(int){1,2}", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 一元表达式
|
||||||
|
{
|
||||||
|
scc_ast_expr_t x = make_identifier("x");
|
||||||
|
|
||||||
|
scc_ast_expr_t pre_inc = make_unary(SCC_AST_OP_PREFIX_INCREMENT, &x);
|
||||||
|
SCC_CHECK_AST(&pre_inc.base, "++x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t pre_dec = make_unary(SCC_AST_OP_PREFIX_DECREMENT, &x);
|
||||||
|
SCC_CHECK_AST(&pre_dec.base, "--x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t addr = make_unary(SCC_AST_OP_ADDRESS_OF, &x);
|
||||||
|
SCC_CHECK_AST(&addr.base, "&x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t deref = make_unary(SCC_AST_OP_INDIRECTION, &x);
|
||||||
|
SCC_CHECK_AST(&deref.base, "*x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t plus = make_unary(SCC_AST_OP_UNARY_PLUS, &x);
|
||||||
|
SCC_CHECK_AST(&plus.base, "+x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t minus = make_unary(SCC_AST_OP_UNARY_MINUS, &x);
|
||||||
|
SCC_CHECK_AST(&minus.base, "-x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t bit_not = make_unary(SCC_AST_OP_BITWISE_NOT, &x);
|
||||||
|
SCC_CHECK_AST(&bit_not.base, "~x", scc_parse_expression);
|
||||||
|
|
||||||
|
scc_ast_expr_t log_not = make_unary(SCC_AST_OP_LOGICAL_NOT, &x);
|
||||||
|
SCC_CHECK_AST(&log_not.base, "!x", scc_parse_expression);
|
||||||
|
|
||||||
|
// sizeof 两种形式
|
||||||
|
// sizeof 表达式
|
||||||
|
scc_ast_expr_t sizeof_expr = {.base.type = SCC_AST_EXPR_SIZE_OF};
|
||||||
|
sizeof_expr.attr_of.expr = &x;
|
||||||
|
SCC_CHECK_AST(&sizeof_expr.base, "sizeof x", scc_parse_expression);
|
||||||
|
|
||||||
|
// sizeof(类型名) 需要构造类型节点,暂时略,用TODO
|
||||||
|
// SCC_CHECK_AST(..., "sizeof(int)", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 类型转换
|
||||||
|
{
|
||||||
|
// (int)x
|
||||||
|
// 需要构造类型节点,这里简化,用TODO
|
||||||
|
// scc_ast_type_t int_type = { .base.type = SCC_AST_TYPE_BUILTIN,
|
||||||
|
// .builtin.type = SCC_AST_BUILTIN_TYPE_INT }; scc_ast_expr_t x =
|
||||||
|
// make_identifier("x"); scc_ast_expr_t cast = { .base.type =
|
||||||
|
// SCC_AST_EXPR_CAST }; cast.cast.type = &int_type; cast.cast.expr = &x;
|
||||||
|
// SCC_CHECK_AST(&cast.base, "(int)x", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 二元运算符(按优先级测试)
|
||||||
|
{
|
||||||
|
scc_ast_expr_t a = make_identifier("a");
|
||||||
|
scc_ast_expr_t b = make_identifier("b");
|
||||||
|
scc_ast_expr_t c = make_identifier("c");
|
||||||
|
scc_ast_expr_t d = make_identifier("d");
|
||||||
|
|
||||||
|
// 乘除模优先级高于加减
|
||||||
|
scc_ast_expr_t mul = make_binary(SCC_AST_OP_MUL, &a, &b);
|
||||||
|
scc_ast_expr_t add = make_binary(SCC_AST_OP_ADD, &mul, &c);
|
||||||
|
SCC_CHECK_AST(&add.base, "a * b + c", scc_parse_expression);
|
||||||
|
|
||||||
|
// 左结合性 a - b - c => (a - b) - c
|
||||||
|
scc_ast_expr_t sub1 = make_binary(SCC_AST_OP_SUB, &a, &b);
|
||||||
|
scc_ast_expr_t sub2 = make_binary(SCC_AST_OP_SUB, &sub1, &c);
|
||||||
|
SCC_CHECK_AST(&sub2.base, "a - b - c", scc_parse_expression);
|
||||||
|
|
||||||
|
// 移位
|
||||||
|
scc_ast_expr_t shift = make_binary(SCC_AST_OP_LEFT_SHIFT, &a, &b);
|
||||||
|
SCC_CHECK_AST(&shift.base, "a << b", scc_parse_expression);
|
||||||
|
|
||||||
|
// 关系
|
||||||
|
scc_ast_expr_t lt = make_binary(SCC_AST_OP_LESS, &a, &b);
|
||||||
|
SCC_CHECK_AST(<.base, "a < b", scc_parse_expression);
|
||||||
|
|
||||||
|
// 相等
|
||||||
|
scc_ast_expr_t eq = make_binary(SCC_AST_OP_EQUAL, &a, &b);
|
||||||
|
SCC_CHECK_AST(&eq.base, "a == b", scc_parse_expression);
|
||||||
|
|
||||||
|
// 按位与、异或、或的优先级:& 高于 ^ 高于 |
|
||||||
|
scc_ast_expr_t bitand = make_binary(SCC_AST_OP_BITWISE_AND, &a, &b);
|
||||||
|
scc_ast_expr_t bitxor =
|
||||||
|
make_binary(SCC_AST_OP_BITWISE_XOR, &bitand, &c);
|
||||||
|
scc_ast_expr_t bitor = make_binary(SCC_AST_OP_BITWISE_OR, &bitxor, &d);
|
||||||
|
SCC_CHECK_AST(&bitor.base, "a & b ^ c | d", scc_parse_expression);
|
||||||
|
|
||||||
|
// 逻辑与、或:&& 高于 ||
|
||||||
|
scc_ast_expr_t logand = make_binary(SCC_AST_OP_LOGICAL_AND, &a, &b);
|
||||||
|
scc_ast_expr_t logor = make_binary(SCC_AST_OP_LOGICAL_OR, &logand, &c);
|
||||||
|
SCC_CHECK_AST(&logor.base, "a && b || c", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 三元运算符
|
||||||
|
{
|
||||||
|
scc_ast_expr_t cond = make_identifier("a");
|
||||||
|
scc_ast_expr_t then_expr = make_identifier("b");
|
||||||
|
scc_ast_expr_t else_expr = make_identifier("c");
|
||||||
|
scc_ast_expr_t cond_expr =
|
||||||
|
make_conditional(&cond, &then_expr, &else_expr);
|
||||||
|
SCC_CHECK_AST(&cond_expr.base, "a ? b : c", scc_parse_expression);
|
||||||
|
|
||||||
|
// 右结合性 a ? b : c ? d : e => a ? b : (c ? d : e)
|
||||||
|
scc_ast_expr_t cond2 = make_identifier("c");
|
||||||
|
scc_ast_expr_t then2 = make_identifier("d");
|
||||||
|
scc_ast_expr_t else2 = make_identifier("e");
|
||||||
|
scc_ast_expr_t inner_cond = make_conditional(&cond2, &then2, &else2);
|
||||||
|
scc_ast_expr_t outer_cond =
|
||||||
|
make_conditional(&cond, &then_expr, &inner_cond);
|
||||||
|
SCC_CHECK_AST(&outer_cond.base, "a ? b : c ? d : e",
|
||||||
|
scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 赋值运算符(右结合)
|
||||||
|
{
|
||||||
|
// scc_ast_expr_t a = make_identifier("a");
|
||||||
|
// scc_ast_expr_t b = make_identifier("b");
|
||||||
|
// scc_ast_expr_t c = make_identifier("c");
|
||||||
|
// scc_ast_expr_t assign1 = make_binary(SCC_AST_OP_ASSIGN, &a, &b);
|
||||||
|
// scc_ast_expr_t assign2 =
|
||||||
|
// make_binary(SCC_AST_OP_ASSIGN, &assign1, &c); // a = (b = c)
|
||||||
|
// SCC_CHECK_AST(&assign2.base, "a = b = c", scc_parse_expression);
|
||||||
|
|
||||||
|
// scc_ast_expr_t add_assign = make_binary(SCC_AST_OP_ASSIGN_ADD, &a,
|
||||||
|
// &b); SCC_CHECK_AST(&add_assign.base, "a += b", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. 逗号运算符
|
||||||
|
{
|
||||||
|
scc_ast_expr_t a = make_identifier("a");
|
||||||
|
scc_ast_expr_t b = make_identifier("b");
|
||||||
|
scc_ast_expr_t comma1 = make_binary(SCC_AST_OP_COMMA, &a, &b);
|
||||||
|
SCC_CHECK_AST(&comma1.base, "a, b", scc_parse_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. 混合优先级测试
|
||||||
|
{
|
||||||
|
scc_ast_expr_t a = make_identifier("a");
|
||||||
|
scc_ast_expr_t b = make_identifier("b");
|
||||||
|
scc_ast_expr_t c = make_identifier("c");
|
||||||
|
scc_ast_expr_t d = make_identifier("d");
|
||||||
|
|
||||||
|
// a + b * c - d => (a + (b * c)) - d
|
||||||
|
scc_ast_expr_t mul = make_binary(SCC_AST_OP_MUL, &b, &c);
|
||||||
|
scc_ast_expr_t add = make_binary(SCC_AST_OP_ADD, &a, &mul);
|
||||||
|
scc_ast_expr_t sub = make_binary(SCC_AST_OP_SUB, &add, &d);
|
||||||
|
SCC_CHECK_AST(&sub.base, "a + b * c - d", scc_parse_expression);
|
||||||
|
|
||||||
|
// *p++ => *(p++)
|
||||||
|
scc_ast_expr_t p = make_identifier("p");
|
||||||
|
scc_ast_expr_t post_inc = make_unary(SCC_AST_OP_POSTFIX_INCREMENT, &p);
|
||||||
|
scc_ast_expr_t deref = make_unary(SCC_AST_OP_INDIRECTION, &post_inc);
|
||||||
|
SCC_CHECK_AST(&deref.base, "*p++", scc_parse_expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_LIST = {
|
||||||
|
{"parser_unit", test_parser_unit},
|
||||||
|
{"parser_expression", test_parser_expression},
|
||||||
|
{NULL, NULL},
|
||||||
|
};
|
||||||
@@ -46,6 +46,8 @@ typedef struct scc_pproc {
|
|||||||
|
|
||||||
scc_lexer_tok_ring_t ring;
|
scc_lexer_tok_ring_t ring;
|
||||||
int ring_ref_count;
|
int ring_ref_count;
|
||||||
|
cbool ring_need_comment;
|
||||||
|
cbool ring_need_empty;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int max_include_depth;
|
int max_include_depth;
|
||||||
@@ -53,7 +55,8 @@ typedef struct scc_pproc {
|
|||||||
} scc_pproc_t;
|
} scc_pproc_t;
|
||||||
|
|
||||||
void scc_pproc_init(scc_pproc_t *pp, scc_lexer_tok_ring_t *input);
|
void scc_pproc_init(scc_pproc_t *pp, scc_lexer_tok_ring_t *input);
|
||||||
scc_lexer_tok_ring_t *scc_pproc_to_ring(scc_pproc_t *pp, int ring_size);
|
scc_lexer_tok_ring_t *scc_pproc_to_ring(scc_pproc_t *pp, int ring_size,
|
||||||
|
cbool need_empty, cbool need_comment);
|
||||||
void scc_pproc_drop(scc_pproc_t *pp);
|
void scc_pproc_drop(scc_pproc_t *pp);
|
||||||
|
|
||||||
static inline void scc_pproc_add_include_path(scc_pproc_t *pp,
|
static inline void scc_pproc_add_include_path(scc_pproc_t *pp,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <pproc_expand.h>
|
#include <pproc_expand.h>
|
||||||
|
#include <scc_lexer.h>
|
||||||
#include <scc_lexer_utils.h>
|
#include <scc_lexer_utils.h>
|
||||||
#include <scc_pproc.h>
|
#include <scc_pproc.h>
|
||||||
|
|
||||||
@@ -120,11 +121,27 @@ void scc_pproc_add_builtin_macros() {
|
|||||||
|
|
||||||
static cbool fill_token(scc_lexer_tok_t *tok, void *userdata) {
|
static cbool fill_token(scc_lexer_tok_t *tok, void *userdata) {
|
||||||
scc_pproc_t *pp = userdata;
|
scc_pproc_t *pp = userdata;
|
||||||
return pproc_next(pp, tok);
|
cbool ret = false;
|
||||||
|
CONTINUE:
|
||||||
|
ret = pproc_next(pp, tok);
|
||||||
|
if (ret && !pp->ring_need_comment &&
|
||||||
|
scc_get_tok_subtype(tok->type) == SCC_TOK_SUBTYPE_COMMENT) {
|
||||||
|
scc_lexer_tok_drop(tok);
|
||||||
|
goto CONTINUE;
|
||||||
|
}
|
||||||
|
if (ret && !pp->ring_need_empty &&
|
||||||
|
scc_get_tok_subtype(tok->type) == SCC_TOK_SUBTYPE_EMPTYSPACE) {
|
||||||
|
scc_lexer_tok_drop(tok);
|
||||||
|
goto CONTINUE;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_lexer_tok_ring_t *scc_pproc_to_ring(scc_pproc_t *pp, int ring_size) {
|
scc_lexer_tok_ring_t *scc_pproc_to_ring(scc_pproc_t *pp, int ring_size,
|
||||||
|
cbool need_empty, cbool need_comment) {
|
||||||
scc_ring_init(pp->ring, ring_size, fill_token, pp);
|
scc_ring_init(pp->ring, ring_size, fill_token, pp);
|
||||||
|
pp->ring_need_comment = need_comment;
|
||||||
|
pp->ring_need_empty = need_empty;
|
||||||
pp->ring_ref_count++;
|
pp->ring_ref_count++;
|
||||||
return &pp->ring;
|
return &pp->ring;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,21 +15,10 @@
|
|||||||
|
|
||||||
// #define ANSI_FMT
|
// #define ANSI_FMT
|
||||||
|
|
||||||
#define SCC_TREE_DUMP_PRINT_COLORED(ctx, color, before_str, fmt, after_str, \
|
|
||||||
...) \
|
|
||||||
scc_printf(before_str "%s" fmt "%s" after_str, \
|
|
||||||
ctx->use_color ? color : "", ##__VA_ARGS__, \
|
|
||||||
ctx->use_color ? ANSI_NONE : "");
|
|
||||||
|
|
||||||
#define SCC_TREE_DUMP_PRINT_AROUND(ctx, color, around_str, fmt, ...) \
|
|
||||||
SCC_TREE_DUMP_PRINT_COLORED(ctx, color, around_str, fmt, around_str, \
|
|
||||||
##__VA_ARGS__)
|
|
||||||
|
|
||||||
#define SCC_TREE_DUMP_PRINT_PURE(ctx, color, fmt, ...) \
|
|
||||||
SCC_TREE_DUMP_PRINT_COLORED(ctx, color, "", fmt, "", ##__VA_ARGS__)
|
|
||||||
|
|
||||||
typedef SCC_VEC(cbool) scc_ast_dump_stack_t;
|
typedef SCC_VEC(cbool) scc_ast_dump_stack_t;
|
||||||
|
|
||||||
|
typedef void (*scc_tree_dump_output_t)(void *userdata, const char *fmt, ...);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
scc_ast_dump_stack_t stack; ///< 每层是否为最后子节点
|
scc_ast_dump_stack_t stack; ///< 每层是否为最后子节点
|
||||||
cbool use_color; ///< 是否使用颜色输出
|
cbool use_color; ///< 是否使用颜色输出
|
||||||
@@ -43,10 +32,15 @@ typedef struct {
|
|||||||
const char *value_color; ///< 值颜色
|
const char *value_color; ///< 值颜色
|
||||||
const char *branch_color; ///< 分支符号颜色
|
const char *branch_color; ///< 分支符号颜色
|
||||||
const char *reset_color; ///< 重置颜色
|
const char *reset_color; ///< 重置颜色
|
||||||
|
|
||||||
|
scc_tree_dump_output_t output_func;
|
||||||
|
void *output_userdata;
|
||||||
} scc_tree_dump_ctx_t;
|
} scc_tree_dump_ctx_t;
|
||||||
|
|
||||||
static inline void scc_tree_dump_ctx_init(scc_tree_dump_ctx_t *ctx,
|
static inline void scc_tree_dump_ctx_init(scc_tree_dump_ctx_t *ctx,
|
||||||
cbool use_color) {
|
cbool use_color,
|
||||||
|
scc_tree_dump_output_t output_func,
|
||||||
|
void *output_userdata) {
|
||||||
ctx->use_color = use_color;
|
ctx->use_color = use_color;
|
||||||
scc_vec_init(ctx->stack);
|
scc_vec_init(ctx->stack);
|
||||||
|
|
||||||
@@ -59,8 +53,14 @@ static inline void scc_tree_dump_ctx_init(scc_tree_dump_ctx_t *ctx,
|
|||||||
ctx->value_color = use_color ? SCC_TREE_DUMP_VALUE_COLOR : "";
|
ctx->value_color = use_color ? SCC_TREE_DUMP_VALUE_COLOR : "";
|
||||||
ctx->branch_color = use_color ? SCC_TREE_DUMP_BRANCH_COLOR : "";
|
ctx->branch_color = use_color ? SCC_TREE_DUMP_BRANCH_COLOR : "";
|
||||||
ctx->reset_color = use_color ? SCC_TREE_DUMP_RESET_COLOR : "";
|
ctx->reset_color = use_color ? SCC_TREE_DUMP_RESET_COLOR : "";
|
||||||
|
|
||||||
|
ctx->output_func = output_func;
|
||||||
|
ctx->output_userdata = output_userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define scc_tree_dump_printf(ctx, fmt, ...) \
|
||||||
|
(ctx)->output_func((ctx)->output_userdata, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
static inline void scc_tree_dump_ctx_drop(scc_tree_dump_ctx_t *ctx) {
|
static inline void scc_tree_dump_ctx_drop(scc_tree_dump_ctx_t *ctx) {
|
||||||
scc_vec_free(ctx->stack);
|
scc_vec_free(ctx->stack);
|
||||||
}
|
}
|
||||||
@@ -78,13 +78,28 @@ static void scc_tree_print_indent(scc_tree_dump_ctx_t *ctx) {
|
|||||||
}
|
}
|
||||||
Assert(data != null);
|
Assert(data != null);
|
||||||
if (ctx->use_color) {
|
if (ctx->use_color) {
|
||||||
scc_printf("%s%s%s", ctx->branch_color, data, ctx->reset_color);
|
ctx->output_func(ctx->output_userdata, "%s%s%s", ctx->branch_color,
|
||||||
|
data, ctx->reset_color);
|
||||||
} else {
|
} else {
|
||||||
scc_printf("%s", data);
|
ctx->output_func(ctx->output_userdata, "%s", data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SCC_TREE_DUMP_PRINT_COLORED(ctx, color, before_str, fmt, after_str, \
|
||||||
|
...) \
|
||||||
|
(ctx)->output_func((ctx)->output_userdata, \
|
||||||
|
before_str "%s" fmt "%s" after_str, \
|
||||||
|
(ctx)->use_color ? color : "", ##__VA_ARGS__, \
|
||||||
|
(ctx)->use_color ? ANSI_NONE : "");
|
||||||
|
|
||||||
|
#define SCC_TREE_DUMP_PRINT_AROUND(ctx, color, around_str, fmt, ...) \
|
||||||
|
SCC_TREE_DUMP_PRINT_COLORED(ctx, color, around_str, fmt, around_str, \
|
||||||
|
##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define SCC_TREE_DUMP_PRINT_PURE(ctx, color, fmt, ...) \
|
||||||
|
SCC_TREE_DUMP_PRINT_COLORED(ctx, color, "", fmt, "", ##__VA_ARGS__)
|
||||||
|
|
||||||
// 推入新的层级到栈中
|
// 推入新的层级到栈中
|
||||||
static inline void scc_tree_dump_push_level(scc_tree_dump_ctx_t *ctx,
|
static inline void scc_tree_dump_push_level(scc_tree_dump_ctx_t *ctx,
|
||||||
cbool is_last_child) {
|
cbool is_last_child) {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ typedef enum {
|
|||||||
SCC_FILE_WRITE,
|
SCC_FILE_WRITE,
|
||||||
SCC_FILE_APPEND,
|
SCC_FILE_APPEND,
|
||||||
} scc_fmode_t;
|
} scc_fmode_t;
|
||||||
|
#define scc_stdout 1
|
||||||
|
#define scc_stderr 2
|
||||||
scc_file_t scc_fopen(const char *path, scc_fmode_t mode);
|
scc_file_t scc_fopen(const char *path, scc_fmode_t mode);
|
||||||
void scc_fclose(scc_file_t file);
|
void scc_fclose(scc_file_t file);
|
||||||
usize scc_fsize(scc_file_t file);
|
usize scc_fsize(scc_file_t file);
|
||||||
|
|||||||
@@ -65,13 +65,39 @@
|
|||||||
(ring).tail++; \
|
(ring).tail++; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 环形缓冲区核心操作模板
|
||||||
|
* @param ring 环形缓冲区变量
|
||||||
|
* @param ok 状态输出变量
|
||||||
|
* @param op 具体操作代码块(可包含多条语句)
|
||||||
|
*
|
||||||
|
* 封装了以下公共逻辑:
|
||||||
|
* 1. 确保缓冲区有数据可用
|
||||||
|
* 2. 检查probe是否越界
|
||||||
|
* 3. 计算物理索引
|
||||||
|
* 4. 执行具体操作
|
||||||
|
*/
|
||||||
|
#define _SCC_RING_OP(ring, ok, op) \
|
||||||
|
do { \
|
||||||
|
_scc_ring_ensure(ring, ok); \
|
||||||
|
if (!(ok)) \
|
||||||
|
break; \
|
||||||
|
if ((ring).probe >= (ring).tail) { \
|
||||||
|
ok = 0; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
usize _phys = _scc_ring_phys(ring, (ring).probe); \
|
||||||
|
(void)_phys; \
|
||||||
|
op; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
// ==================== 用户操作宏 ====================
|
// ==================== 用户操作宏 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 初始化环形缓冲区
|
* @brief 初始化环形缓冲区
|
||||||
* @param ring 环形缓冲区变量
|
* @param ring 环形缓冲区变量
|
||||||
* @param cap 容量
|
* @param cap 容量
|
||||||
* @param fill_func 填充回调函数 (可传 NULL)
|
* @param fill_func 填充回调函数 (可传 NULL) 返回true表示成功
|
||||||
*
|
*
|
||||||
* 内存分配失败由 scc_malloc 内部处理 (如 LOG_FATAL)
|
* 内存分配失败由 scc_malloc 内部处理 (如 LOG_FATAL)
|
||||||
*/
|
*/
|
||||||
@@ -116,17 +142,16 @@
|
|||||||
* @param ok 变量名,用于接收成功状态 (cbool 类型)
|
* @param ok 变量名,用于接收成功状态 (cbool 类型)
|
||||||
*/
|
*/
|
||||||
#define scc_ring_peek(ring, val, ok) \
|
#define scc_ring_peek(ring, val, ok) \
|
||||||
do { \
|
_SCC_RING_OP(ring, ok, val = (ring).data[_phys])
|
||||||
_scc_ring_ensure(ring, ok); \
|
|
||||||
if (!(ok)) \
|
/**
|
||||||
break; \
|
* @brief 预览 probe 位置的引用 (不移动 probe)
|
||||||
if ((ring).probe >= (ring).tail) { \
|
* @param ring 环形缓冲区变量
|
||||||
ok = 0; \
|
* @param val_ref 引用变量接收地址
|
||||||
break; \
|
* @param ok 变量名,用于接收成功状态
|
||||||
} \
|
*/
|
||||||
usize _phys = _scc_ring_phys(ring, (ring).probe); \
|
#define scc_ring_unsafe_peek_ref(ring, val_ref, ok) \
|
||||||
val = (ring).data[_phys]; \
|
_SCC_RING_OP(ring, ok, val_ref = &((ring).data[_phys]))
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取 probe 位置的元素,并将 probe 前进一步
|
* @brief 获取 probe 位置的元素,并将 probe 前进一步
|
||||||
@@ -135,18 +160,41 @@
|
|||||||
* @param ok 变量名,用于接收成功状态 (cbool 类型)
|
* @param ok 变量名,用于接收成功状态 (cbool 类型)
|
||||||
*/
|
*/
|
||||||
#define scc_ring_next(ring, val, ok) \
|
#define scc_ring_next(ring, val, ok) \
|
||||||
do { \
|
_SCC_RING_OP(ring, ok, val = (ring).data[_phys]; (ring).probe++)
|
||||||
_scc_ring_ensure(ring, ok); \
|
|
||||||
if (!(ok)) \
|
/**
|
||||||
break; \
|
* @brief 获取 probe 位置的引用,并将 probe 前进一步
|
||||||
if ((ring).probe >= (ring).tail) { \
|
* @param ring 环形缓冲区变量
|
||||||
ok = 0; \
|
* @param val 引用变量接收地址
|
||||||
break; \
|
* @param ok 变量名,用于接收成功状态
|
||||||
} \
|
*/
|
||||||
usize _phys = _scc_ring_phys(ring, (ring).probe); \
|
#define scc_ring_unsafe_next_ref(ring, val, ok) \
|
||||||
val = (ring).data[_phys]; \
|
_SCC_RING_OP(ring, ok, val = &((ring).data[_phys]); (ring).probe++)
|
||||||
(ring).probe++; \
|
|
||||||
} while (0)
|
/**
|
||||||
|
* @brief 获取元素并消费(移动 probe 和 head)
|
||||||
|
* @param ring 环形缓冲区变量
|
||||||
|
* @param val 变量名,用于接收元素值
|
||||||
|
* @param ok 变量名,用于接收成功状态
|
||||||
|
*/
|
||||||
|
#define scc_ring_next_consume(ring, val, ok) \
|
||||||
|
_SCC_RING_OP(ring, ok, val = (ring).data[_phys]; (ring).probe++; \
|
||||||
|
(ring).head = (ring).probe)
|
||||||
|
|
||||||
|
#define scc_ring_unsafe_pure_next_consume(ring) \
|
||||||
|
_SCC_RING_OP(ring, ok, (ring).probe++; (ring).head = (ring).probe)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取元素并消费(移动 probe 和 head)
|
||||||
|
* @param ring 环形缓冲区变量
|
||||||
|
* @param val 变量名,用于接收元素值
|
||||||
|
* @param ok 变量名,用于接收成功状态
|
||||||
|
*/
|
||||||
|
#define scc_ring_unsafe_next_ref_consume(ring, val, ok) \
|
||||||
|
_SCC_RING_OP(ring, ok, val = &((ring).data[_phys]); (ring).probe++; \
|
||||||
|
(ring).head = (ring).probe)
|
||||||
|
|
||||||
|
#define scc_ring_not_eof(ring, ok) _SCC_RING_OP(ring, ok, )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 将 probe 后退一步 (不能低于 head)
|
* @brief 将 probe 后退一步 (不能低于 head)
|
||||||
@@ -182,16 +230,4 @@
|
|||||||
*/
|
*/
|
||||||
#define scc_ring_available(ring) ((ring).tail - (ring).probe)
|
#define scc_ring_available(ring) ((ring).tail - (ring).probe)
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取 probe 位置的元素,并将 probe 前进一步同时标记为已消费
|
|
||||||
* @param ring 环形缓冲区变量
|
|
||||||
* @param val 变量名,用于接收元素值 (例如 int ch)
|
|
||||||
* @param ok 变量名,用于接收成功状态 (cbool 类型)
|
|
||||||
*/
|
|
||||||
#define scc_ring_next_consume(ring, val, ok) \
|
|
||||||
do { \
|
|
||||||
scc_ring_next(ring, val, ok); \
|
|
||||||
scc_ring_consume(ring); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif /* __SCC_CORE_RING_H__ */
|
#endif /* __SCC_CORE_RING_H__ */
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
#define __SCC_LOG_IMPL_IMPORT_SRC__
|
#define __SCC_LOG_IMPL_IMPORT_SRC__
|
||||||
#include <scc_core_log.h>
|
#include <scc_core_log.h>
|
||||||
|
|
||||||
#define scc_stdout 1
|
|
||||||
#define scc_stderr 2
|
|
||||||
|
|
||||||
void putchar_(char ch) { LOG_FATAL("you can't use printf.c directly"); }
|
void putchar_(char ch) { LOG_FATAL("you can't use printf.c directly"); }
|
||||||
|
|
||||||
scc_file_t scc_fopen(const char *path, scc_fmode_t mode) {
|
scc_file_t scc_fopen(const char *path, scc_fmode_t mode) {
|
||||||
|
|||||||
43
src/main.c
43
src/main.c
@@ -2,8 +2,8 @@
|
|||||||
#include <scc_lexer.h>
|
#include <scc_lexer.h>
|
||||||
#include <scc_pproc.h>
|
#include <scc_pproc.h>
|
||||||
|
|
||||||
// #include <scc_parser.h>
|
#include <ast_dump.h>
|
||||||
// #include <ast_dump.h>
|
#include <scc_parser.h>
|
||||||
// #include <ir_dump.h>
|
// #include <ir_dump.h>
|
||||||
// #include <scc_ast2ir.h>
|
// #include <scc_ast2ir.h>
|
||||||
|
|
||||||
@@ -195,12 +195,11 @@ int main(int argc, const char **argv, const char **envp) {
|
|||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifndef SCC_DEFAULT_ARGPARSE_LANG
|
||||||
#define OUTPUT_DEFAULT_FILE "a.exe"
|
#define SCC_DEFAULT_ARGPARSE_LANG SCC_ARGPARSE_LANG_ZH
|
||||||
#else
|
|
||||||
#define OUTPUT_DEFAULT_FILE "a.out"
|
|
||||||
#endif
|
#endif
|
||||||
scc_argparse_lang_t argparse_lang = SCC_ARGPARSE_LANG_EN;
|
|
||||||
|
scc_argparse_lang_t argparse_lang = SCC_DEFAULT_ARGPARSE_LANG;
|
||||||
for (const char **env = envp; *env != null; env++) {
|
for (const char **env = envp; *env != null; env++) {
|
||||||
const char *env_str = *env;
|
const char *env_str = *env;
|
||||||
if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) {
|
if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) {
|
||||||
@@ -256,7 +255,8 @@ int main(int argc, const char **argv, const char **envp) {
|
|||||||
scc_pproc_add_object_macro(&(pproc.macro_table), &pproc_macro_name,
|
scc_pproc_add_object_macro(&(pproc.macro_table), &pproc_macro_name,
|
||||||
&pproc_tok_vec);
|
&pproc_tok_vec);
|
||||||
if (config.emit_pp) {
|
if (config.emit_pp) {
|
||||||
scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pproc, 8);
|
scc_lexer_tok_ring_t *tok_ring =
|
||||||
|
scc_pproc_to_ring(&pproc, 8, true, true);
|
||||||
if (config.output_file == null) {
|
if (config.output_file == null) {
|
||||||
print_ring(tok_ring, config.verbose);
|
print_ring(tok_ring, config.verbose);
|
||||||
} else {
|
} else {
|
||||||
@@ -265,22 +265,25 @@ int main(int argc, const char **argv, const char **envp) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pproc, 8, false, false);
|
||||||
|
scc_parser_t parser;
|
||||||
|
scc_parser_init(&parser, tok_ring, null);
|
||||||
|
scc_ast_translation_unit_t *translation_unit =
|
||||||
|
scc_parse_translation_unit(&parser);
|
||||||
|
|
||||||
|
scc_parser_drop(&parser);
|
||||||
scc_pproc_drop(&pproc);
|
scc_pproc_drop(&pproc);
|
||||||
scc_lexer_drop(&lexer);
|
scc_lexer_drop(&lexer);
|
||||||
scc_sstream_drop(&sstream);
|
scc_sstream_drop(&sstream);
|
||||||
|
|
||||||
// scc_parser_t parser;
|
if (config.emit_ast) {
|
||||||
// scc_parser_init(&parser, &lexer_stream, null);
|
scc_tree_dump_ctx_t tree_dump;
|
||||||
// scc_ast_translation_unit_t *translation_unit =
|
scc_tree_dump_ctx_init(&tree_dump, true, (void *)scc_fprintf,
|
||||||
// scc_parse_translation_unit(&parser);
|
(void *)scc_stdout);
|
||||||
|
scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit);
|
||||||
// if (config.emit_ast) {
|
scc_tree_dump_ctx_drop(&tree_dump);
|
||||||
// scc_tree_dump_ctx_t tree_dump;
|
return 0;
|
||||||
// scc_tree_dump_ctx_init(&tree_dump, true);
|
}
|
||||||
// scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit);
|
|
||||||
// scc_tree_dump_ctx_drop(&tree_dump);
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// scc_ir_builder_t ir_builder;
|
// scc_ir_builder_t ir_builder;
|
||||||
// scc_ast2ir(translation_unit, &ir_builder);
|
// scc_ast2ir(translation_unit, &ir_builder);
|
||||||
|
|||||||
1
tests/simple/00_main.c
Normal file
1
tests/simple/00_main.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
int main(void) {}
|
||||||
Reference in New Issue
Block a user