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:
zzy
2026-01-28 15:44:24 +08:00
parent 84cff78b86
commit e1cd8c5206
12 changed files with 2035 additions and 157 deletions

View File

@@ -6,17 +6,21 @@
typedef enum scc_cstd { typedef enum scc_cstd {
SCC_CSTD_C89, SCC_CSTD_C89,
SCC_CSTD_C99, SCC_CSTD_C99,
SCC_CEXT_ASM, SCC_CEXT_SCC,
} scc_cstd_t; } scc_cstd_t;
/* clang-format off */ /* clang-format off */
// WARNING: Using Binary Search To Fast Find Keyword // WARNING: Using Binary Search To Fast Find Keyword
// 你必须确保其中是按照字典序排列 // 你必须确保其中是按照字典序排列
#define SCC_CKEYWORD_TABLE \ #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(break , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_BREAK , SCC_CSTD_C89) \
X(case , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CASE , 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(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(const , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CONST , SCC_CSTD_C89) \
X(continue , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_CONTINUE , 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) \ X(default , SCC_TOK_SUBTYPE_KEYWORD , SCC_TOK_DEFAULT , SCC_CSTD_C89) \

View File

@@ -92,7 +92,7 @@ static void parse_line(scc_lexer_t *lexer, scc_lexer_tok_t *token) {
if (scc_probe_stream_consume(stream) != ' ') { if (scc_probe_stream_consume(stream) != ' ') {
scc_lex_parse_skip_line(stream, &lexer->pos); 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) != '"') { 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); scc_probe_stream_reset(stream);
if (scc_lex_parse_number(stream, &lexer->pos, &output) == true) { if (scc_lex_parse_number(stream, &lexer->pos, &output) == true) {
scc_probe_stream_sync(stream); scc_probe_stream_sync(stream);
token->value.n = output; token->value.u = output;
} else { } else {
LEX_ERROR("Unexpected number literal"); LEX_ERROR("Unexpected number literal");
token->type = SCC_TOK_UNKNOWN; token->type = SCC_TOK_UNKNOWN;

View File

@@ -1,63 +1,60 @@
#include <log.h> #include <log.h>
void log_default_handler(log_level_t level, const char *module, static inline int log_snprintf(char *s, size_t n, const char *format, ...) {
const char *file, int line, const char *message) { int ret;
const char *level_str; va_list args;
switch (level) { va_start(args, format);
case LOG_LEVEL_DEBUG: ret = log_vsnprintf(s, n, format, args);
level_str = "DEBUG"; va_end(args);
break; return ret;
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__ 会取消颜色输出 int log_default_handler(logger_t *module, log_level_t level, const char *file,
#ifndef __LOG_NO_COLOR__ 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; const char *color_code;
switch (level) { switch (level) {
case LOG_LEVEL_DEBUG: case LOG_LEVEL_DEBUG: color_code = ANSI_FG_CYAN; break;
color_code = ANSI_FG_CYAN; case LOG_LEVEL_INFO: color_code = ANSI_FG_GREEN; break;
break; case LOG_LEVEL_TRACE: color_code = ANSI_FG_BLUE; break;
case LOG_LEVEL_INFO: case LOG_LEVEL_WARN: color_code = ANSI_FG_YELLOW; break;
color_code = ANSI_FG_GREEN; case LOG_LEVEL_ERROR: color_code = ANSI_FG_RED; break;
break; case LOG_LEVEL_FATAL: color_code = ANSI_FG_RED ANSI_UNDERLINED; break;
case LOG_LEVEL_TRACE: default: color_code = ANSI_NONE;
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;
} }
/* clang-format on */
log_printf(ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n", color_code, offset =
level_str, module, file, line, message); 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 #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 #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 // for clangd warning
// clang-analyzer-deadcode.DeadStores // clang-analyzer-deadcode.DeadStores
(void)color_code; (void)color_code;
@@ -65,6 +62,7 @@ void log_default_handler(log_level_t level, const char *module,
if (level & LOG_LEVEL_FATAL) { if (level & LOG_LEVEL_FATAL) {
log_exit(-LOG_LEVEL_FATAL); log_exit(-LOG_LEVEL_FATAL);
} }
return 0;
} }
logger_t __default_logger_root = { logger_t __default_logger_root = {

View File

@@ -3,17 +3,18 @@
* @brief 日志系统核心模块(支持多级日志、断言和异常处理) * @brief 日志系统核心模块(支持多级日志、断言和异常处理)
*/ */
#ifndef __SCC_LOG_H__ #ifndef __SCC_LOG_IMPL_H__
#define __SCC_LOG_H__ #define __SCC_LOG_IMPL_H__
#include "color.h" #include "color.h"
#include <stdarg.h>
#ifdef __SCC_LOG_USE_STD_IMPL__ #ifdef __SCC_LOG_IMPL_USE_STD_IMPL__
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define log_snprintf snprintf #define log_vsnprintf vsnprintf
#define log_printf printf #define log_puts puts
#define log_exit exit #define log_exit scc_exit
#endif #endif
#ifdef __GNUC__ // GCC, Clang, ICC #ifdef __GNUC__ // GCC, Clang, ICC
@@ -26,14 +27,14 @@
#define __smcc_log_unreachable() #define __smcc_log_unreachable()
#endif #endif
#ifndef log_snprintf #ifndef log_vsnprintf
#define log_snprintf(...) #define log_vsnprintf(...)
#warning "log_snprintf not defined" #warning "log_vsnprintf not defined"
#endif #endif
#ifndef log_printf #ifndef log_puts
#define log_printf(...) #define log_puts(...)
#warning "log_printf not defined" #warning "log_puts not defined"
#endif #endif
#ifndef log_exit #ifndef log_exit
@@ -57,36 +58,30 @@ typedef enum log_level {
LOG_LEVEL_ALL = 0xFF, ///< 全级别标志(组合所有日志级别) LOG_LEVEL_ALL = 0xFF, ///< 全级别标志(组合所有日志级别)
} log_level_t; } 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 #ifndef LOGGER_MAX_BUF_SIZE
#define LOGGER_MAX_BUF_SIZE 512 ///< 单条日志最大缓冲区尺寸 #define LOGGER_MAX_BUF_SIZE 512 ///< 单条日志最大缓冲区尺寸
#endif #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 日志器实例结构体 * @brief 日志器实例结构体
* *
* 每个日志器实例维护独立的配置和缓冲区 * 每个日志器实例维护独立的配置和缓冲区
*/ */
typedef struct logger { struct logger {
const char *name; ///< 日志器名称(用于模块区分) const char *name; ///< 日志器名称(用于模块区分)
log_level_t level; ///< 当前设置的日志级别 log_level_t level; ///< 当前设置的日志级别
log_handler handler; ///< 日志处理回调函数 log_handler handler; ///< 日志处理回调函数
char buf[LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区 char buf[LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区
} logger_t; };
void log_default_handler(log_level_t level, const char *module, int log_default_handler(logger_t *module, log_level_t level, const char *file,
const char *file, int line, const char *message); int line, const char *func, const char *fmt, ...);
extern logger_t __default_logger_root; 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 ///< 宏展开缓冲区尺寸 #define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE ///< 宏展开缓冲区尺寸
#endif #endif
/** #define SCC_LOG_HANDLE_ARGS(_module_, _level_, ...) \
* @def _LOG (_module_), (_level_), __FILE__, __LINE__, __func__, ##__VA_ARGS__
* @brief 内部日志宏(供其他日志宏调用)
* @param _module_ 模块实例NULL表示使用默认日志器 #define SCC_LOG_IMPL(_module_, _level_, _fmt_, ...) \
* @param _level_ 日志级别
* @param _msg_ 格式字符串
* @param ... 可变参数列表
*/
#define _LOG(_module_, _level_, _msg_, ...) \
do { \ do { \
logger_t *_logger = _module_; \ /* TODO check _module_ is NULL */ \
if (_logger && _logger->handler && (_logger->level & (_level_))) { \ if ((_module_)->handler && ((_module_)->level & (_level_))) \
log_snprintf(_logger->buf, sizeof(_logger->buf), (_msg_), \ (_module_)->handler( \
##__VA_ARGS__); \ SCC_LOG_HANDLE_ARGS(_module_, _level_, _fmt_, ##__VA_ARGS__)); \
_logger->handler((_level_), _logger->name, __FILE__, __LINE__, \
_logger->buf); \
} \
} while (0) } while (0)
/* clang-format off */ /* clang-format off */
/// @name 模块日志宏 /// @name 模块日志宏
/// @{ /// @{
#define MLOG_NOTSET(module, ...)_LOG(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志 #define MLOG_NOTSET(module, ...)SCC_LOG_IMPL(module, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
#define MLOG_DEBUG(module, ...) _LOG(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志需启用DEBUG级别 #define MLOG_DEBUG(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志需启用DEBUG级别
#define MLOG_INFO(module, ...) _LOG(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志) #define MLOG_INFO(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
#define MLOG_WARN(module, ...) _LOG(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题) #define MLOG_WARN(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
#define MLOG_ERROR(module, ...) _LOG(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误) #define MLOG_ERROR(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
#define MLOG_FATAL(module, ...) _LOG(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前) #define MLOG_FATAL(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
#define MLOG_TRACE(module, ...) _LOG(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪) #define MLOG_TRACE(module, ...) SCC_LOG_IMPL(module, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
/// @} /// @}
/// @name 快捷日志宏 /// @name 快捷日志宏
/// @{ /// @{
#define LOG_NOTSET(...) _LOG(&__default_logger_root, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志 #define LOG_NOTSET(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志
#define LOG_DEBUG(...) _LOG(&__default_logger_root, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志需启用DEBUG级别 #define LOG_DEBUG(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志需启用DEBUG级别
#define LOG_INFO(...) _LOG(&__default_logger_root, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志) #define LOG_INFO(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志)
#define LOG_WARN(...) _LOG(&__default_logger_root, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题) #define LOG_WARN(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题)
#define LOG_ERROR(...) _LOG(&__default_logger_root, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误) #define LOG_ERROR(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误)
#define LOG_FATAL(...) _LOG(&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前) #define LOG_FATAL(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前)
#define LOG_TRACE(...) _LOG(&__default_logger_root, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪) #define LOG_TRACE(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪)
/// @} /// @}
/* clang-format on */ /* clang-format on */
@@ -164,35 +151,48 @@ void log_set_handler(logger_t *logger, log_handler handler);
* @param ... 错误信息参数(格式字符串+参数) * @param ... 错误信息参数(格式字符串+参数)
*/ */
#define _Assert(cond, ...) \ #define _Assert(cond, ...) \
do { \ ((void)((cond) || \
if (!(cond)) { \ (__default_logger_root.handler(SCC_LOG_HANDLE_ARGS( \
LOG_FATAL(__VA_ARGS__); \ &__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__)), \
log_exit(1); \ log_exit(1), __smcc_log_unreachable(), 0)))
__smcc_log_unreachable(); \
} \
} while (0)
/// @name 断言工具宏 /// @name 断言工具宏
/// @{ /// @{
#define __INNER_LOG_STR(str) #str #define __INNERSCC_LOG_IMPL_STR(str) #str
#define __LOG_STR(str) __INNER_LOG_STR(str) #define _SCC_LOG_IMPL_STR(str) __INNERSCC_LOG_IMPL_STR(str)
#define AssertFmt(cond, format, ...) \ #define AssertFmt(cond, format, ...) \
_Assert(cond, "Assertion Failure: " format, \ _Assert(cond, "Assertion Failure: " format, \
##__VA_ARGS__) ///< 带格式的断言检查 ##__VA_ARGS__) ///< 带格式的断言检查
#define PanicFmt(format, ...) \ #define PanicFmt(format, ...) \
_Assert(0, "Panic: " format, ##__VA_ARGS__) ///< 立即触发致命错误 _Assert(0, "Panic: " format, ##__VA_ARGS__) ///< 立即触发致命错误
#define Assert(cond) \ #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 Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
#define TODO() \ #define TODO() \
PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误) PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误)
#define UNREACHABLE() PanicFmt("UNREACHABLE") ///< 触发致命错误(代码不可达) #define UNREACHABLE() PanicFmt("UNREACHABLE") ///< 触发致命错误(代码不可达)
#define FIXME(str) \ #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" #include "log.c"
#endif #endif
#endif /* __SCC_LOG_H__ */ #endif /* __SCC_LOG_IMPL_H__ */

File diff suppressed because it is too large Load Diff

View 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_ */

View File

@@ -3,35 +3,31 @@
#include "scc_core_type.h" #include "scc_core_type.h"
/* ====== 内存管理核心接口 ====== */
void *scc_malloc(usize size); void *scc_malloc(usize size);
void *scc_calloc(usize count, usize size); void *scc_calloc(usize count, usize size);
void *scc_realloc(void *ptr, usize new_size); void *scc_realloc(void *ptr, usize new_size);
void scc_free(void *ptr); void scc_free(void *ptr);
/* ====== 文件系统核心接口 ====== */
/* 文件句柄 - 不透明指针 */
typedef struct scc_file *scc_file_t; typedef struct scc_file *scc_file_t;
/* 文件打开模式 - 只保留编译器真正需要的 */
typedef enum { typedef enum {
SCC_FILE_READ, /* 读取源文件、头文件 */ SCC_FILE_READ, /* 读取源文件、头文件 */
SCC_FILE_WRITE, /* 写入目标文件、汇编文件 */ SCC_FILE_WRITE, /* 写入目标文件、汇编文件 */
SCC_FILE_APPEND /* 日志、调试输出 */ SCC_FILE_APPEND /* 日志、调试输出 */
} scc_fmode_t; } scc_fmode_t;
/* 核心文件操作 */
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_fread(scc_file_t file, void *buffer, usize size); usize scc_fread(scc_file_t file, void *buffer, usize size);
usize scc_fwrite(scc_file_t file, const void *buffer, usize size); usize scc_fwrite(scc_file_t file, const void *buffer, usize size);
cbool scc_fexists(const char *path); cbool scc_fexists(const char *path);
/* ====== 输入输出核心接口 ====== */ #include "printf/printf.h"
#define scc_snprintf snprintf_
void scc_snprintf(char *buf, usize size, const char *format, ...); #define scc_vsnprintf vsnprintf_
#ifdef __SCC_CORE_FMT_IMPL__
#include "printf/printf.c"
#endif
/* 标准输出 - 用于编译进度、结果 */ /* 标准输出 - 用于编译进度、结果 */
void scc_printf(const char *format, ...); void scc_printf(const char *format, ...);
@@ -39,8 +35,6 @@ void scc_printf(const char *format, ...);
/* 错误输出 - 用于错误信息、警告 */ /* 错误输出 - 用于错误信息、警告 */
void scc_eprintf(const char *format, ...); void scc_eprintf(const char *format, ...);
/* ====== 系统核心接口 ====== */
/* 程序控制 */ /* 程序控制 */
void scc_exit(int code); void scc_exit(int code);

View File

@@ -1,12 +1,12 @@
#ifndef __SCC_CORE_LOG_H__ #ifndef __SCC_CORE_LOG_H__
#define __SCC_CORE_LOG_H__ #define __SCC_CORE_LOG_H__
#ifndef log_snprintf #ifndef log_vsnprintf
#define log_snprintf scc_snprintf #define log_vsnprintf scc_vsnprintf
#endif #endif
#ifndef log_printf #ifndef log_puts
#define log_printf scc_printf #define log_puts(str) scc_printf("%s", str)
#endif #endif
#ifndef log_exit #ifndef log_exit

View File

@@ -58,7 +58,8 @@ typedef union scc_cvalue {
char ch; char ch;
/* number value */ /* number value */
uint64_t n; uint64_t u;
int64_t i;
/* string value */ /* string value */
struct { struct {

View File

View File

@@ -2,10 +2,11 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#define __SCC_CORE_FMT_IMPL__
#include <scc_core_impl.h> #include <scc_core_impl.h>
#define __SCC_LOG_IMPORT_SRC__ #define __SCC_LOG_IMPL_IMPORT_SRC__
#define log_snprintf scc_snprintf #define log_vsnprintf vsnprintf_
#define log_printf scc_printf #define log_puts(str) scc_printf("%s", str)
#define log_exit scc_exit #define log_exit scc_exit
#include <log.h> #include <log.h>
@@ -15,6 +16,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
void putchar_(char c) { putchar(c); }
/* ====== 内存管理核心接口实现 ====== */ /* ====== 内存管理核心接口实现 ====== */
void *scc_malloc(usize size) { return malloc(size); } void *scc_malloc(usize size) { return malloc(size); }
@@ -71,15 +73,6 @@ cbool scc_fexists(const char *path) {
return true; 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, ...) { void scc_printf(const char *format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);

View File

@@ -1,4 +1,4 @@
#include <libcore.h> #include <scc_core.h>
#include <stdio.h> #include <stdio.h>
int main(void) { int main(void) {