力的黑暗面是通往許多能力的途徑,有些人認為是不自然的。
- 達斯·西迪斯(Darth Sidious)
基於examples/demo.c :
| 編譯時列表操縱 |
// 3, 3, 3, 3, 3
static int five_threes [] = {
ML99_LIST_EVAL_COMMA_SEP ( ML99_listReplicate ( v ( 5 ), v ( 3 ))),
};
// 5, 4, 3, 2, 1
static int from_5_to_1 [] = {
ML99_LIST_EVAL_COMMA_SEP ( ML99_listReverse ( ML99_list ( v ( 1 , 2 , 3 , 4 , 5 )))),
};
// 9, 2, 5
static int lesser_than_10 [] = {
ML99_LIST_EVAL_COMMA_SEP (
ML99_listFilter ( ML99_appl ( v ( ML99_greater ), v ( 10 )), ML99_list ( v ( 9 , 2 , 11 , 13 , 5 )))),
}; |
| 宏遞歸 |
#define factorial ( n ) ML99_natMatch(n, v(factorial_))
#define factorial_Z_IMPL (...) v(1)
#define factorial_S_IMPL ( n ) ML99_mul(ML99_inc(v(n)), factorial(v(n)))
ML99_ASSERT_EQ ( factorial ( v ( 4 )), v ( 24 )); |
| 多個參數過載 |
typedef struct {
double width , height ;
} Rect ;
#define Rect_new (...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__)
#define Rect_new_1 ( x )
{ x, x }
#define Rect_new_2 ( x , y )
{ x, y }
static Rect _7x8 = Rect_new ( 7 , 8 ), _10x10 = Rect_new ( 10 );
// ... and more!
int main ( void ) {
// Yeah. All is done at compile time.
} |
(提示: v(something)評估something 。)
Metalang99是在純C99中編寫可靠且可維護的元圖的堅定基礎。它被實現為預處理宏的解釋性FP語言:Just #include <metalang99.h> ,您已經準備好了。 Metalang99具有代數數據類型,模式匹配,遞歸,咖哩和集合;此外,它提供了用於編譯時間錯誤報告和調試的手段。借助我們內置的語法檢查器,宏錯誤應該是完全可理解的,使您可以方便地開發。
當前,MetalAng99在OpenIPC上用作Datatype99和Interface99的間接依賴性;這包括RTSP 1.0實現以及〜50K的私有代碼行。
宏可促進代碼重複使用,宏是使您塑造語言以適合解決問題的建築材料,從而導致更加干淨和簡潔的代碼。但是,C中的元編程被完全cast割:我們甚至無法使用控制流,整數,無界序列和復合數據結構進行操作,從而從範圍中拋出了許多假設有用的元圖。
為了解決問題,我實施了Metalang99。具有我們可以使用的功能,甚至有可能開發相當不平凡的元圖,例如datatype99:
#include <datatype99.h>
datatype (
BinaryTree ,
( Leaf , int ),
( Node , BinaryTree * , int , BinaryTree * )
);
int sum ( const BinaryTree * tree ) {
match ( * tree ) {
of ( Leaf , x ) return * x ;
of ( Node , lhs , x , rhs ) return sum ( * lhs ) + * x + sum ( * rhs );
}
return -1 ;
}或接口99:
#include <interface99.h>
#include <stdio.h>
#define Shape_IFACE
vfunc( int, perim, const VSelf)
vfunc(void, scale, VSelf, int factor)
interface ( Shape );
typedef struct {
int a , b ;
} Rectangle ;
int Rectangle_perim ( const VSelf ) { /* ... */ }
void Rectangle_scale ( VSelf , int factor ) { /* ... */ }
impl ( Shape , Rectangle );
typedef struct {
int a , b , c ;
} Triangle ;
int Triangle_perim ( const VSelf ) { /* ... */ }
void Triangle_scale ( VSelf , int factor ) { /* ... */ }
impl ( Shape , Triangle );
void test ( Shape shape ) {
printf ( "perim = %dn" , VCALL ( shape , perim ));
VCALL ( shape , scale , 5 );
printf ( "perim = %dn" , VCALL ( shape , perim ));
}與模糊的技術(例如標記的工會或虛擬方法表)不同,上述元圖可利用類型安全性,語法簡潔性,並保持生成代碼的確切內存佈局。
看起來很有趣嗎?查看勵志帖子以獲取更多信息。
Metalang99只是一組標頭文件,別無其他。要將其用作依賴性,您需要:
metalang99/include目錄。-ftrack-macro-expansion=0 (gcc)或-fmacro-backtrace-limit=1 (clang),以避免無用的宏擴展錯誤。如果使用cmake,則建議的方法是FetchContent :
include (FetchContent)
FetchContent_Declare(
metalang99
URL https://github.com/hirrolot/metalang99/archive/refs/tags/v1.2.3.tar.gz # v1.2.3
)
FetchContent_MakeAvailable(metalang99)
target_link_libraries (MyProject metalang99)
# Disable full macro expansion backtraces for Metalang99.
if (CMAKE_C_COMPILER_ID STREQUAL "Clang" )
target_compile_options (MyProject PRIVATE -fmacro-backtrace-limit=1)
elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU" )
target_compile_options (MyProject PRIVATE -ftrack-macro-expansion=0)
endif ()可選的是,您可以預編譯依賴MetalAng99的標題。這將減少彙編時間,因為每次包含標題時都不會編譯標題。
教程|示例|用戶文檔
快樂黑客!
宏遞歸。遞歸電話的行為如預期。特別是,為了實施遞歸,提升/預處理器僅將所有遞歸功能複製到一定限制,並將其力量跟踪遞歸深度或依靠其內置扣除。作為口譯員,Metalang99沒有此類缺點。
幾乎相同的語法。與PP順序相比,Metalang99看起來不太陌生,因為語法與通常的預處理器代碼無關。
部分申請。 MetalAng99的部分應用程序無需在這里和那裡跟踪輔助參數(如在Boost/Preadotersor中完成),可以首先應用常數值來捕獲環境。除此之外,部分應用還有助於更好地重用元功能。請參閱ML99_const , ML99_compose等。
調試和錯誤報告。您可以使用ML99_abort方便地調試宏,並通過ML99_fatal報告無法恢復的錯誤。口譯員將立即停止並實現困難。據我們所知,沒有其他宏觀框架為調試和錯誤報告提供了這種機制。
我在Poica上的工作是在BOOST/PEDORACERSOR上實施的研究計劃語言,使我對結果不滿意。 Boost/預處理器的基本局限性使代碼庫完全無法實現。其中包括遞歸宏通話(被預處理器阻止),這使調試一場噩夢,缺乏部分應用程序,使上下文完全尷尬,以及導致編譯器錯誤消息的兆字節。
只有那時,我已經理解,我們不應該真正建立一個清晰的範式來構造元圖的清晰範式。考慮到這些想法,我開始實施Metalang99 ...
長話短說,釋放v0.1.0的艱苦努力花費了一半的努力,並使其穩定了近一年。作為MetalAng99的真實應用程序,我完全以相同的形式創建了DataType99:實現是高度聲明性的,語法很漂亮,語義是明確的。
最後,我想說的是,Metalang99僅與語法轉換有關,而不是關於CPU結合的任務。預處理器太慢且有限,無法進行這種虐待。
ML99_assertIsTuple , ML99_assertIsNat等主張宏參數,以進行良好的形式,以提供更好的診斷消息。ML99_cat或其朋友,更喜歡##令牌運算符,因為儘管如此,爭論仍會得到充分擴展。ML99_todo及其朋友指示未完成功能。 參見CONTRIBUTING.md 。
請參閱ARCHITECTURE.md 。
參見idioms.md 。
請參閱optimization_tips.md 。
答:Metalang99是邁向可理解的編譯器診斷的重要一步。它具有內置的語法檢查器,該檢查器測試所有傳入術語的有效性:
[ playground.c ]
ML99_EVAL ( 123 )
ML99_EVAL ( x , y , z )
ML99_EVAL ( v ( Billie ) v ( Jean )) [ /bin/sh ]
$ gcc playground.c -Imetalang99/include -ftrack-macro-expansion=0
playground.c:3:1: error: static assertion failed: "invalid term `123`"
3 | ML99_EVAL(123)
| ^~~~~~~~~
playground.c:4:1: error: static assertion failed: "invalid term `x`"
4 | ML99_EVAL(x, y, z)
| ^~~~~~~~~
playground.c:5:1: error: static assertion failed: "invalid term `(0v, Billie) (0v, Jean)`, did you miss a comma?"
5 | ML99_EVAL(v(Billie) v(Jean))
| ^~~~~~~~~
Metalang99甚至可以檢查是否有宏觀前提並報告錯誤:
[ playground.c ]
ML99_EVAL ( ML99_listHead ( ML99_nil ()))
ML99_EVAL ( ML99_unwrapLeft ( ML99_right ( v ( 123 ))))
ML99_EVAL ( ML99_div ( v ( 18 ), v ( 4 ))) [ /bin/sh ]
$ gcc playground.c -Imetalang99/include -ftrack-macro-expansion=0
playground.c:3:1: error: static assertion failed: "ML99_listHead: expected a non-empty list"
3 | ML99_EVAL(ML99_listHead(ML99_nil()))
| ^~~~~~~~~
playground.c:4:1: error: static assertion failed: "ML99_unwrapLeft: expected ML99_left but found ML99_right"
4 | ML99_EVAL(ML99_unwrapLeft(ML99_right(v(123))))
| ^~~~~~~~~
playground.c:5:1: error: static assertion failed: "ML99_div: 18 is not divisible by 4"
5 | ML99_EVAL(ML99_div(v(18), v(4)))
| ^~~~~~~~~
但是,如果您做一些尷尬的事情,編譯時錯誤可能會變得非常晦澀:
// ML99_PRIV_REC_NEXT_ML99_PRIV_IF_0 blah(ML99_PRIV_SYNTAX_CHECKER_EMIT_ERROR, ML99_PRIV_TERM_MATCH) ((~, ~, ~) blah, ML99_PRIV_EVAL_)(ML99_PRIV_REC_STOP, (~), 0fspace, (, ), ((0end, ~), ~), ~, ~ blah)(0)()
ML99_EVAL ((~, ~, ~) blah )無論哪種情況,您都可以嘗試迭代地調試您的元圖。根據我的經驗,有95%的錯誤是可理解的 - Metalang99是為人類而不是用於宏觀怪物的。
答:請參閱“測試,調試和錯誤報告”一章。
答:我使用VS代碼進行開發。它可以實現宏觀生成構造的彈出建議,但當然,它不支持宏觀語法突出顯示。
答:要運行基準,請從根目錄中執行./scripts/bench.sh 。
一個:
答:請參閱博客文章“實際上,C預處理器的重點是什麼?”
答:C/C ++預處理器能夠僅迭代一定限制。對於MetalAng99,該限制是根據減排步驟定義的:一旦固定數量的減少步驟耗盡,您的元數據將無法再執行。
答:Metalang99主要針對純C,C缺少模板。但是無論如何,您可以在BOOST/Preprocessor的網站上找到C ++的論點。
答:由於更新的負擔,我反對合併的標題。取而代之的是,您只需添加Metalang99作為GIT subsodule,然後使用git submodule update --remote進行更新。
答:C99/C ++ 11及以後。
答:已知Metalang99可以在這些編譯器上使用: