feat(lexer): 添加SCC语言扩展关键字支持并重构标准定义
- 将SCC_CEXT_ASM重命名为SCC_CEXT_SCC以更好地反映扩展类型 - 为asm关键字添加SCC_CEXT_SCC标准标识 - 新增atomic、auto、bool、complex四个关键字及其对应的token类型 - 所有新关键字都标记为SCC_CEXT_SCC扩展标准 fix(lexer): 修复数字字面量解析中的类型不匹配问题 - 将token->value.n更正为token->value.u以正确存储解析结果 - 统一了词法分析器中数值解析的字段访问 refactor(log): 重构日志系统API设计并增强功能 - 将日志处理器接口从void返回改为int返回类型 - 新增函数名记录功能,通过__func__宏获取当前函数名 - 引入可变参数支持,允许格式化字符串传递 - 重构内部宏实现,使用SCC_LOG_IMPL统一处理逻辑 - 改进缓冲区管理,优化日志消息格式化流程 - 重命名头文件保护宏从__SCC_LOG_H__到__SCC_LOG_IMPL_H__ - 替换snprintf为vsnprintf以支持可变参数处理 - 更新断言宏实现,提供更清晰的错误信息格式
This commit is contained in:
@@ -6,17 +6,21 @@
|
||||
typedef enum scc_cstd {
|
||||
SCC_CSTD_C89,
|
||||
SCC_CSTD_C99,
|
||||
SCC_CEXT_ASM,
|
||||
SCC_CEXT_SCC,
|
||||
} scc_cstd_t;
|
||||
|
||||
/* clang-format off */
|
||||
// WARNING: Using Binary Search To Fast Find Keyword
|
||||
// 你必须确保其中是按照字典序排列
|
||||
#define SCC_CKEYWORD_TABLE \
|
||||
X(asm , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_ASM , SCC_CEXT_ASM) \
|
||||
X(asm , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_ASM , SCC_CEXT_SCC) \
|
||||
X(atomic , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_ATOMIC , SCC_CEXT_SCC) \
|
||||
X(auto , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_AUTO , SCC_CEXT_SCC) \
|
||||
X(bool , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_BOOL , SCC_CEXT_SCC) \
|
||||
X(break , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_BREAK , SCC_CSTD_C89) \
|
||||
X(case , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CASE , SCC_CSTD_C89) \
|
||||
X(char , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CHAR , SCC_CSTD_C89) \
|
||||
X(complex , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_COMPLEX , SCC_CEXT_SCC) \
|
||||
X(const , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CONST , SCC_CSTD_C89) \
|
||||
X(continue , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CONTINUE , SCC_CSTD_C89) \
|
||||
X(default , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_DEFAULT , SCC_CSTD_C89) \
|
||||
|
||||
@@ -92,7 +92,7 @@ static void parse_line(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
|
||||
|
||||
if (scc_probe_stream_consume(stream) != ' ') {
|
||||
scc_lex_parse_skip_line(stream, &lexer->pos);
|
||||
token->loc.line = token->value.n;
|
||||
token->loc.line = token->value.u;
|
||||
}
|
||||
|
||||
if (scc_probe_stream_next(stream) != '"') {
|
||||
@@ -385,7 +385,7 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
|
||||
scc_probe_stream_reset(stream);
|
||||
if (scc_lex_parse_number(stream, &lexer->pos, &output) == true) {
|
||||
scc_probe_stream_sync(stream);
|
||||
token->value.n = output;
|
||||
token->value.u = output;
|
||||
} else {
|
||||
LEX_ERROR("Unexpected number literal");
|
||||
token->type = SCC_TOK_UNKNOWN;
|
||||
|
||||
@@ -1,63 +1,60 @@
|
||||
#include <log.h>
|
||||
|
||||
void log_default_handler(log_level_t level, const char *module,
|
||||
const char *file, int line, const char *message) {
|
||||
const char *level_str;
|
||||
switch (level) {
|
||||
case LOG_LEVEL_DEBUG:
|
||||
level_str = "DEBUG";
|
||||
break;
|
||||
case LOG_LEVEL_INFO:
|
||||
level_str = "INFO ";
|
||||
break;
|
||||
case LOG_LEVEL_WARN:
|
||||
level_str = "WARN ";
|
||||
break;
|
||||
case LOG_LEVEL_ERROR:
|
||||
level_str = "ERROR";
|
||||
break;
|
||||
case LOG_LEVEL_FATAL:
|
||||
level_str = "FATAL";
|
||||
break;
|
||||
case LOG_LEVEL_TRACE:
|
||||
level_str = "TRACE";
|
||||
break;
|
||||
default:
|
||||
level_str = "NOTSET";
|
||||
break;
|
||||
static inline int log_snprintf(char *s, size_t n, const char *format, ...) {
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
ret = log_vsnprintf(s, n, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int log_default_handler(logger_t *module, log_level_t level, const char *file,
|
||||
int line, const char *func, const char *fmt, ...) {
|
||||
const char *level_str;
|
||||
int offset = 0;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
/* clang-format off */
|
||||
switch (level) {
|
||||
case LOG_LEVEL_DEBUG: level_str = "DEBUG"; break;
|
||||
case LOG_LEVEL_INFO: level_str = "INFO "; break;
|
||||
case LOG_LEVEL_WARN: level_str = "WARN "; break;
|
||||
case LOG_LEVEL_ERROR: level_str = "ERROR"; break;
|
||||
case LOG_LEVEL_FATAL: level_str = "FATAL"; break;
|
||||
case LOG_LEVEL_TRACE: level_str = "TRACE"; break;
|
||||
default: level_str = "NOTSET"; break;
|
||||
}
|
||||
/// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出
|
||||
#ifndef __LOG_NO_COLOR__
|
||||
const char *color_code;
|
||||
switch (level) {
|
||||
case LOG_LEVEL_DEBUG:
|
||||
color_code = ANSI_FG_CYAN;
|
||||
break;
|
||||
case LOG_LEVEL_INFO:
|
||||
color_code = ANSI_FG_GREEN;
|
||||
break;
|
||||
case LOG_LEVEL_TRACE:
|
||||
color_code = ANSI_FG_BLUE;
|
||||
break;
|
||||
case LOG_LEVEL_WARN:
|
||||
color_code = ANSI_FG_YELLOW;
|
||||
break;
|
||||
case LOG_LEVEL_ERROR:
|
||||
color_code = ANSI_FG_RED;
|
||||
break;
|
||||
case LOG_LEVEL_FATAL:
|
||||
color_code = ANSI_FG_RED ANSI_UNDERLINED;
|
||||
break; // 增强对比度
|
||||
default:
|
||||
color_code = ANSI_NONE;
|
||||
case LOG_LEVEL_DEBUG: color_code = ANSI_FG_CYAN; break;
|
||||
case LOG_LEVEL_INFO: color_code = ANSI_FG_GREEN; break;
|
||||
case LOG_LEVEL_TRACE: color_code = ANSI_FG_BLUE; break;
|
||||
case LOG_LEVEL_WARN: color_code = ANSI_FG_YELLOW; break;
|
||||
case LOG_LEVEL_ERROR: color_code = ANSI_FG_RED; break;
|
||||
case LOG_LEVEL_FATAL: color_code = ANSI_FG_RED ANSI_UNDERLINED; break;
|
||||
default: color_code = ANSI_NONE;
|
||||
}
|
||||
|
||||
log_printf(ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n", color_code,
|
||||
level_str, module, file, line, message);
|
||||
/* clang-format on */
|
||||
offset =
|
||||
log_snprintf(module->buf, sizeof(module->buf),
|
||||
ANSI_BOLD "%s[%s] %s - %s:%d in %s()" ANSI_NONE " ",
|
||||
color_code, level_str, module->name, file, line, func);
|
||||
#else
|
||||
log_printf("[%s] %s:%d | %s: %s\n", level_str, file, line, module, message);
|
||||
offset = log_snprintf(module->buf, sizeof(module->buf),
|
||||
"[%s] %s - %s:%d in %s() ", level_str, module->name,
|
||||
file, line, func);
|
||||
#endif
|
||||
/* 然后写入用户消息(如果有) */
|
||||
if (fmt && fmt[0]) {
|
||||
log_vsnprintf(module->buf + offset, sizeof(module->buf) - offset, fmt,
|
||||
args);
|
||||
}
|
||||
va_end(args);
|
||||
log_puts(module->buf);
|
||||
log_puts("\n");
|
||||
// for clangd warning
|
||||
// clang-analyzer-deadcode.DeadStores
|
||||
(void)color_code;
|
||||
@@ -65,6 +62,7 @@ void log_default_handler(log_level_t level, const char *module,
|
||||
if (level & LOG_LEVEL_FATAL) {
|
||||
log_exit(-LOG_LEVEL_FATAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
logger_t __default_logger_root = {
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
* @brief 日志系统核心模块(支持多级日志、断言和异常处理)
|
||||
*/
|
||||
|
||||
#ifndef __SCC_LOG_H__
|
||||
#define __SCC_LOG_H__
|
||||
#ifndef __SCC_LOG_IMPL_H__
|
||||
#define __SCC_LOG_IMPL_H__
|
||||
|
||||
#include "color.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __SCC_LOG_USE_STD_IMPL__
|
||||
#ifdef __SCC_LOG_IMPL_USE_STD_IMPL__
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define log_snprintf snprintf
|
||||
#define log_printf printf
|
||||
#define log_exit exit
|
||||
#define log_vsnprintf vsnprintf
|
||||
#define log_puts puts
|
||||
#define log_exit scc_exit
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__ // GCC, Clang, ICC
|
||||
@@ -26,14 +27,14 @@
|
||||
#define __smcc_log_unreachable()
|
||||
#endif
|
||||
|
||||
#ifndef log_snprintf
|
||||
#define log_snprintf(...)
|
||||
#warning "log_snprintf not defined"
|
||||
#ifndef log_vsnprintf
|
||||
#define log_vsnprintf(...)
|
||||
#warning "log_vsnprintf not defined"
|
||||
#endif
|
||||
|
||||
#ifndef log_printf
|
||||
#define log_printf(...)
|
||||
#warning "log_printf not defined"
|
||||
#ifndef log_puts
|
||||
#define log_puts(...)
|
||||
#warning "log_puts not defined"
|
||||
#endif
|
||||
|
||||
#ifndef log_exit
|
||||
@@ -57,36 +58,30 @@ typedef enum log_level {
|
||||
LOG_LEVEL_ALL = 0xFF, ///< 全级别标志(组合所有日志级别)
|
||||
} log_level_t;
|
||||
|
||||
/**
|
||||
* @brief 日志处理回调函数类型
|
||||
* @param level 日志级别
|
||||
* @param module 模块名称(可为NULL)
|
||||
* @param file 源文件名
|
||||
* @param line 代码行号
|
||||
* @param message 格式化后的日志消息
|
||||
* @todo 待实现模块名称,输入的模块名称,都将被忽略
|
||||
*/
|
||||
typedef void (*log_handler)(log_level_t level, const char *module,
|
||||
const char *file, int line, const char *message);
|
||||
|
||||
#ifndef LOGGER_MAX_BUF_SIZE
|
||||
#define LOGGER_MAX_BUF_SIZE 512 ///< 单条日志最大缓冲区尺寸
|
||||
#endif
|
||||
|
||||
typedef struct logger logger_t;
|
||||
|
||||
typedef int (*log_handler)(logger_t *module, log_level_t level,
|
||||
const char *file, int line, const char *func,
|
||||
const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief 日志器实例结构体
|
||||
*
|
||||
* 每个日志器实例维护独立的配置和缓冲区
|
||||
*/
|
||||
typedef struct logger {
|
||||
struct logger {
|
||||
const char *name; ///< 日志器名称(用于模块区分)
|
||||
log_level_t level; ///< 当前设置的日志级别
|
||||
log_handler handler; ///< 日志处理回调函数
|
||||
char buf[LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区
|
||||
} logger_t;
|
||||
};
|
||||
|
||||
void log_default_handler(log_level_t level, const char *module,
|
||||
const char *file, int line, const char *message);
|
||||
int log_default_handler(logger_t *module, log_level_t level, const char *file,
|
||||
int line, const char *func, const char *fmt, ...);
|
||||
extern logger_t __default_logger_root;
|
||||
|
||||
/**
|
||||
@@ -114,46 +109,38 @@ void log_set_handler(logger_t *logger, log_handler handler);
|
||||
#define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE ///< 宏展开缓冲区尺寸
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def _LOG
|
||||
* @brief 内部日志宏(供其他日志宏调用)
|
||||
* @param _module_ 模块实例(NULL表示使用默认日志器)
|
||||
* @param _level_ 日志级别
|
||||
* @param _msg_ 格式字符串
|
||||
* @param ... 可变参数列表
|
||||
*/
|
||||
#define _LOG(_module_, _level_, _msg_, ...) \
|
||||
#define SCC_LOG_HANDLE_ARGS(_module_, _level_, ...) \
|
||||
(_module_), (_level_), __FILE__, __LINE__, __func__, ##__VA_ARGS__
|
||||
|
||||
#define SCC_LOG_IMPL(_module_, _level_, _fmt_, ...) \
|
||||
do { \
|
||||
logger_t *_logger = _module_; \
|
||||
if (_logger && _logger->handler && (_logger->level & (_level_))) { \
|
||||
log_snprintf(_logger->buf, sizeof(_logger->buf), (_msg_), \
|
||||
##__VA_ARGS__); \
|
||||
_logger->handler((_level_), _logger->name, __FILE__, __LINE__, \
|
||||
_logger->buf); \
|
||||
} \
|
||||
/* TODO check _module_ is NULL */ \
|
||||
if ((_module_)->handler && ((_module_)->level & (_level_))) \
|
||||
(_module_)->handler( \
|
||||
SCC_LOG_HANDLE_ARGS(_module_, _level_, _fmt_, ##__VA_ARGS__)); \
|
||||
} while (0)
|
||||
|
||||
/* clang-format off */
|
||||
/// @name 模块日志宏
|
||||
/// @{
|
||||
#define MLOG_NOTSET(module, ...)_LOG(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
|
||||
#define MLOG_DEBUG(module, ...) _LOG(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别)
|
||||
#define MLOG_INFO(module, ...) _LOG(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
|
||||
#define MLOG_WARN(module, ...) _LOG(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
|
||||
#define MLOG_ERROR(module, ...) _LOG(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
|
||||
#define MLOG_FATAL(module, ...) _LOG(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
|
||||
#define MLOG_TRACE(module, ...) _LOG(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
|
||||
#define MLOG_NOTSET(module, ...)SCC_LOG_IMPL(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
|
||||
#define MLOG_DEBUG(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别)
|
||||
#define MLOG_INFO(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
|
||||
#define MLOG_WARN(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
|
||||
#define MLOG_ERROR(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
|
||||
#define MLOG_FATAL(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
|
||||
#define MLOG_TRACE(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
|
||||
/// @}
|
||||
|
||||
/// @name 快捷日志宏
|
||||
/// @{
|
||||
#define LOG_NOTSET(...) _LOG(&__default_logger_root, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
|
||||
#define LOG_DEBUG(...) _LOG(&__default_logger_root, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别)
|
||||
#define LOG_INFO(...) _LOG(&__default_logger_root, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
|
||||
#define LOG_WARN(...) _LOG(&__default_logger_root, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
|
||||
#define LOG_ERROR(...) _LOG(&__default_logger_root, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
|
||||
#define LOG_FATAL(...) _LOG(&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
|
||||
#define LOG_TRACE(...) _LOG(&__default_logger_root, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
|
||||
#define LOG_NOTSET(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
|
||||
#define LOG_DEBUG(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别)
|
||||
#define LOG_INFO(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
|
||||
#define LOG_WARN(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
|
||||
#define LOG_ERROR(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
|
||||
#define LOG_FATAL(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
|
||||
#define LOG_TRACE(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
|
||||
/// @}
|
||||
/* clang-format on */
|
||||
|
||||
@@ -164,35 +151,48 @@ void log_set_handler(logger_t *logger, log_handler handler);
|
||||
* @param ... 错误信息参数(格式字符串+参数)
|
||||
*/
|
||||
#define _Assert(cond, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
LOG_FATAL(__VA_ARGS__); \
|
||||
log_exit(1); \
|
||||
__smcc_log_unreachable(); \
|
||||
} \
|
||||
} while (0)
|
||||
((void)((cond) || \
|
||||
(__default_logger_root.handler(SCC_LOG_HANDLE_ARGS( \
|
||||
&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__)), \
|
||||
log_exit(1), __smcc_log_unreachable(), 0)))
|
||||
|
||||
/// @name 断言工具宏
|
||||
/// @{
|
||||
#define __INNER_LOG_STR(str) #str
|
||||
#define __LOG_STR(str) __INNER_LOG_STR(str)
|
||||
#define __INNERSCC_LOG_IMPL_STR(str) #str
|
||||
#define _SCC_LOG_IMPL_STR(str) __INNERSCC_LOG_IMPL_STR(str)
|
||||
#define AssertFmt(cond, format, ...) \
|
||||
_Assert(cond, "Assertion Failure: " format, \
|
||||
##__VA_ARGS__) ///< 带格式的断言检查
|
||||
#define PanicFmt(format, ...) \
|
||||
_Assert(0, "Panic: " format, ##__VA_ARGS__) ///< 立即触发致命错误
|
||||
#define Assert(cond) \
|
||||
AssertFmt(cond, "cond is `" __LOG_STR(cond) "`") ///< 基础断言检查
|
||||
AssertFmt(cond, "cond is `" _SCC_LOG_IMPL_STR(cond) "`") ///< 基础断言检查
|
||||
#define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
|
||||
#define TODO() \
|
||||
PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误)
|
||||
#define UNREACHABLE() PanicFmt("UNREACHABLE") ///< 触发致命错误(代码不可达)
|
||||
#define FIXME(str) \
|
||||
PanicFmt("FIXME " __LOG_STR(str)) ///< 提醒开发者修改代码(触发致命错误)
|
||||
PanicFmt("FIXME " _SCC_LOG_IMPL_STR( \
|
||||
str)) ///< 提醒开发者修改代码(触发致命错误)
|
||||
/// @}
|
||||
|
||||
#ifdef __SCC_LOG_IMPORT_SRC__
|
||||
/**
|
||||
* @brief 静态断言(编译时)
|
||||
*
|
||||
* 利用数组大小不能为负的特性
|
||||
* 或使用 _Static_assert (C11)
|
||||
*/
|
||||
#ifdef static_assert
|
||||
#undef static_assert
|
||||
#endif
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define static_assert _Static_assert
|
||||
#else
|
||||
#define static_assert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
#ifdef __SCC_LOG_IMPL_IMPORT_SRC__
|
||||
#include "log.c"
|
||||
#endif
|
||||
|
||||
#endif /* __SCC_LOG_H__ */
|
||||
#endif /* __SCC_LOG_IMPL_H__ */
|
||||
|
||||
1646
runtime/scc_core/include/printf/printf.c
Normal file
1646
runtime/scc_core/include/printf/printf.c
Normal file
File diff suppressed because it is too large
Load Diff
242
runtime/scc_core/include/printf/printf.h
Normal file
242
runtime/scc_core/include/printf/printf.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
|
||||
* 2021-2024, Haifa, Palestine/Israel
|
||||
* @author (c) Marco Paland (info@paland.com)
|
||||
* 2014-2019, PALANDesign Hannover, Germany
|
||||
*
|
||||
* @note Others have made smaller contributions to this file: see the
|
||||
* contributors page at https://github.com/eyalroz/printf/graphs/contributors
|
||||
* or ask one of the authors.
|
||||
*
|
||||
* @brief Small stand-alone implementation of the printf family of functions
|
||||
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems
|
||||
* with a very limited resources.
|
||||
*
|
||||
* @note the implementations are thread-safe; re-entrant; use no functions from
|
||||
* the standard library; and do not dynamically allocate any memory.
|
||||
*
|
||||
* @license The MIT License (MIT)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PRINTF_H_
|
||||
#define PRINTF_H_
|
||||
|
||||
#ifdef PRINTF_INCLUDE_CONFIG_H
|
||||
#include "printf_config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <cstdarg>
|
||||
# include <cstddef>
|
||||
extern "C" {
|
||||
#else
|
||||
# include <stdarg.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# if ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
|
||||
# define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||
__attribute__((format(gnu_printf, (one_based_format_index), (first_arg))))
|
||||
# else
|
||||
# define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||
__attribute__((format(printf, (one_based_format_index), (first_arg))))
|
||||
# endif
|
||||
# define ATTR_VPRINTF(one_based_format_index) \
|
||||
ATTR_PRINTF((one_based_format_index), 0)
|
||||
#else
|
||||
# define ATTR_PRINTF(one_based_format_index, first_arg)
|
||||
# define ATTR_VPRINTF(one_based_format_index)
|
||||
#endif
|
||||
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 0
|
||||
#endif
|
||||
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
# define printf_ printf
|
||||
# define sprintf_ sprintf
|
||||
# define vsprintf_ vsprintf
|
||||
# define snprintf_ snprintf
|
||||
# define vsnprintf_ vsnprintf
|
||||
# define vprintf_ vprintf
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If you want to include this implementation file directly rather than
|
||||
* link against it, this will let you control the functions' visibility,
|
||||
* e.g. make them static so as not to clash with other objects also
|
||||
* using them.
|
||||
*/
|
||||
#ifndef PRINTF_VISIBILITY
|
||||
#define PRINTF_VISIBILITY
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Prints/send a single character to some opaque output entity
|
||||
*
|
||||
* @note This function is not implemented by the library, only declared; you
|
||||
* must provide an implementation if you wish to use the @ref printf / @ref
|
||||
* vprintf function (and possibly for linking against the library, if your
|
||||
* toolchain does not support discarding unused functions)
|
||||
*
|
||||
* @note The output could be as simple as a wrapper for the `write()` system
|
||||
* call on a Unix-like * system, or even libc's @ref putchar , for replicating
|
||||
* actual functionality of libc's @ref printf * function; but on an embedded
|
||||
* system it may involve interaction with a special output device, like a UART,
|
||||
* etc.
|
||||
*
|
||||
* @note in libc's @ref putchar, the parameter type is an int; this was intended
|
||||
* to support the representation of either a proper character or EOF in a
|
||||
* variable - but this is really not meaningful to pass into @ref putchar and is
|
||||
* discouraged today. See further discussion in:
|
||||
* @link https://stackoverflow.com/q/17452847/1593077
|
||||
*
|
||||
* @param c the single character to print
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
void putchar_(char c);
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's printf/vprintf
|
||||
*
|
||||
* @note you must implement a @ref putchar_ function for using this function -
|
||||
* it invokes @ref putchar_ * rather than directly performing any I/O (which
|
||||
* insulates it from any dependence on the operating system * and external
|
||||
* libraries).
|
||||
*
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each %-specifier in
|
||||
* @p format
|
||||
* @return The number of characters written into @p s, not counting the
|
||||
* terminating null character
|
||||
*/
|
||||
/* @{ */
|
||||
PRINTF_VISIBILITY
|
||||
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
|
||||
PRINTF_VISIBILITY
|
||||
int vprintf_(const char* format, va_list arg) ATTR_VPRINTF(1);
|
||||
/* @} */
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's sprintf/vsprintf
|
||||
*
|
||||
* @note For security considerations (the potential for exceeding the buffer
|
||||
* bounds), please consider using the size-constrained variant, @ref snprintf /
|
||||
* @ref vsnprintf, instead.
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large
|
||||
* enough to fit the formatted output!
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters written into @p s, not counting the
|
||||
* terminating null character
|
||||
*/
|
||||
/* @{ */
|
||||
PRINTF_VISIBILITY
|
||||
int sprintf_(char* s, const char* format, ...) ATTR_PRINTF(2, 3);
|
||||
PRINTF_VISIBILITY
|
||||
int vsprintf_(char* s, const char* format, va_list arg) ATTR_VPRINTF(2);
|
||||
/* @} */
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's snprintf/vsnprintf
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large
|
||||
* enough to fit either the entire formatted output, or at least @p n
|
||||
* characters. Alternatively, it can be NULL, in which case nothing will
|
||||
* be printed, and only the number of characters which _could_ have been
|
||||
* printed is tallied and returned.
|
||||
* @param n The maximum number of characters to write to the array, including
|
||||
* a terminating null character
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters that COULD have been written into @p s, not
|
||||
* counting the terminating null character. A value equal or larger than
|
||||
* @p n indicates truncation. Only when the returned value is non-negative
|
||||
* and less than @p n, the null-terminated string has been fully and
|
||||
* successfully printed.
|
||||
*/
|
||||
/* @{ */
|
||||
PRINTF_VISIBILITY
|
||||
int snprintf_(char* s, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vsnprintf_(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* printf/vprintf with user-specified output function
|
||||
*
|
||||
* An alternative to @ref printf_, in which the output function is specified
|
||||
* dynamically (rather than @ref putchar_ being used)
|
||||
*
|
||||
* @param out An output function which takes one character and a type-erased
|
||||
* additional parameters
|
||||
* @param extra_arg The type-erased argument to pass to the output function @p
|
||||
* out with each call
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters for which the output f unction was invoked,
|
||||
* not counting the terminating null character
|
||||
*
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
int fctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vfctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg) ATTR_VPRINTF(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
# undef printf_
|
||||
# undef sprintf_
|
||||
# undef vsprintf_
|
||||
# undef snprintf_
|
||||
# undef vsnprintf_
|
||||
# undef vprintf_
|
||||
#else
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
||||
# define printf printf_
|
||||
# define sprintf sprintf_
|
||||
# define vsprintf vsprintf_
|
||||
# define snprintf snprintf_
|
||||
# define vsnprintf vsnprintf_
|
||||
# define vprintf vprintf_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* PRINTF_H_ */
|
||||
@@ -3,35 +3,31 @@
|
||||
|
||||
#include "scc_core_type.h"
|
||||
|
||||
/* ====== 内存管理核心接口 ====== */
|
||||
|
||||
void *scc_malloc(usize size);
|
||||
void *scc_calloc(usize count, usize size);
|
||||
void *scc_realloc(void *ptr, usize new_size);
|
||||
void scc_free(void *ptr);
|
||||
|
||||
/* ====== 文件系统核心接口 ====== */
|
||||
|
||||
/* 文件句柄 - 不透明指针 */
|
||||
typedef struct scc_file *scc_file_t;
|
||||
|
||||
/* 文件打开模式 - 只保留编译器真正需要的 */
|
||||
typedef enum {
|
||||
SCC_FILE_READ, /* 读取源文件、头文件 */
|
||||
SCC_FILE_WRITE, /* 写入目标文件、汇编文件 */
|
||||
SCC_FILE_APPEND /* 日志、调试输出 */
|
||||
} scc_fmode_t;
|
||||
|
||||
/* 核心文件操作 */
|
||||
scc_file_t scc_fopen(const char *path, scc_fmode_t mode);
|
||||
void scc_fclose(scc_file_t file);
|
||||
usize scc_fread(scc_file_t file, void *buffer, usize size);
|
||||
usize scc_fwrite(scc_file_t file, const void *buffer, usize size);
|
||||
cbool scc_fexists(const char *path);
|
||||
|
||||
/* ====== 输入输出核心接口 ====== */
|
||||
|
||||
void scc_snprintf(char *buf, usize size, const char *format, ...);
|
||||
#include "printf/printf.h"
|
||||
#define scc_snprintf snprintf_
|
||||
#define scc_vsnprintf vsnprintf_
|
||||
#ifdef __SCC_CORE_FMT_IMPL__
|
||||
#include "printf/printf.c"
|
||||
#endif
|
||||
|
||||
/* 标准输出 - 用于编译进度、结果 */
|
||||
void scc_printf(const char *format, ...);
|
||||
@@ -39,8 +35,6 @@ void scc_printf(const char *format, ...);
|
||||
/* 错误输出 - 用于错误信息、警告 */
|
||||
void scc_eprintf(const char *format, ...);
|
||||
|
||||
/* ====== 系统核心接口 ====== */
|
||||
|
||||
/* 程序控制 */
|
||||
void scc_exit(int code);
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef __SCC_CORE_LOG_H__
|
||||
#define __SCC_CORE_LOG_H__
|
||||
|
||||
#ifndef log_snprintf
|
||||
#define log_snprintf scc_snprintf
|
||||
#ifndef log_vsnprintf
|
||||
#define log_vsnprintf scc_vsnprintf
|
||||
#endif
|
||||
|
||||
#ifndef log_printf
|
||||
#define log_printf scc_printf
|
||||
#ifndef log_puts
|
||||
#define log_puts(str) scc_printf("%s", str)
|
||||
#endif
|
||||
|
||||
#ifndef log_exit
|
||||
|
||||
@@ -58,7 +58,8 @@ typedef union scc_cvalue {
|
||||
|
||||
char ch;
|
||||
/* number value */
|
||||
uint64_t n;
|
||||
uint64_t u;
|
||||
int64_t i;
|
||||
|
||||
/* string value */
|
||||
struct {
|
||||
|
||||
0
runtime/scc_core/src/cfg.bale_metal.c
Normal file
0
runtime/scc_core/src/cfg.bale_metal.c
Normal file
@@ -2,10 +2,11 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#define __SCC_CORE_FMT_IMPL__
|
||||
#include <scc_core_impl.h>
|
||||
#define __SCC_LOG_IMPORT_SRC__
|
||||
#define log_snprintf scc_snprintf
|
||||
#define log_printf scc_printf
|
||||
#define __SCC_LOG_IMPL_IMPORT_SRC__
|
||||
#define log_vsnprintf vsnprintf_
|
||||
#define log_puts(str) scc_printf("%s", str)
|
||||
#define log_exit scc_exit
|
||||
#include <log.h>
|
||||
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void putchar_(char c) { putchar(c); }
|
||||
/* ====== 内存管理核心接口实现 ====== */
|
||||
|
||||
void *scc_malloc(usize size) { return malloc(size); }
|
||||
@@ -71,15 +73,6 @@ cbool scc_fexists(const char *path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ====== 输入输出核心接口实现 ====== */
|
||||
|
||||
void scc_snprintf(char *buf, usize size, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buf, size, format, args); // NOLINT
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void scc_printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <libcore.h>
|
||||
#include <scc_core.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
Reference in New Issue
Block a user