ด้านมืดของพลังเป็นเส้นทางสู่ความสามารถมากมายบางคนคิดว่าผิดธรรมชาติ
- 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 เป็นรากฐานที่มั่นคงสำหรับการเขียน metaprograms ที่เชื่อถือได้และบำรุงรักษาใน C99 บริสุทธิ์ มันถูกนำมาใช้เป็นภาษา FP ที่ตีความบนมาโครตัวประมวลผลล่วงหน้า: แค่ #include <metalang99.h> และคุณพร้อมที่จะไป MetalAng99 มีประเภทข้อมูลพีชคณิตการจับคู่รูปแบบการเรียกซ้ำการแกงกะหรี่และคอลเลกชัน นอกจากนี้ยังมีวิธีการสำหรับการรายงานข้อผิดพลาดเวลารวบรวมและการดีบัก ด้วยตัวตรวจสอบไวยากรณ์ในตัวของเราข้อผิดพลาดมาโครควรเข้าใจได้อย่างสมบูรณ์แบบช่วยให้คุณสามารถพัฒนาได้อย่างสะดวก
ปัจจุบัน MetalAng99 ถูกใช้ที่ OpenIPC เป็นการพึ่งพาทางอ้อมของ DataType99 และ Interface99; ซึ่งรวมถึงการใช้งาน RTSP 1.0 พร้อมกับรหัสส่วนตัว ~ 50K บรรทัด
มาโครอำนวยความสะดวกในการใช้รหัสซ้ำมาโครเป็นวัสดุก่อสร้างที่ช่วยให้คุณกำหนดภาษาให้เหมาะสมกับปัญหาที่ได้รับการแก้ไขนำไปสู่รหัสที่สะอาดและรัดกุมมากขึ้น อย่างไรก็ตาม metaprogramming ใน C นั้นตอนที่สมบูรณ์: เราไม่สามารถใช้งานได้กับการไหลของการควบคุมจำนวนเต็มลำดับที่ไม่มีขอบเขตและโครงสร้างข้อมูลแบบผสมดังนั้นจึงมีการขว้าง metaprograms ที่มีประโยชน์มากมาย
เพื่อแก้ปัญหาฉันได้ใช้งาน MetalAng99 การมีฟังก์ชั่นในการกำจัดของเรามันเป็นไปได้ที่จะพัฒนาแม้กระทั่ง metaprograms ที่ไม่สำคัญเช่น 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 ));
}ซึ่งแตกต่างจากเทคนิคที่คลุมเครือเช่นสหภาพที่ติดแท็กหรือตารางวิธีการเสมือนจริง metaprograms ด้านบนใช้ความปลอดภัยประเภทความปลอดภัยไวยากรณ์ความกระชับและรักษาเค้าโครงหน่วยความจำที่แน่นอนของรหัสที่สร้างขึ้น
ดูน่าสนใจ? ตรวจสอบโพสต์ที่สร้างแรงบันดาลใจสำหรับข้อมูลเพิ่มเติม
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 สิ่งนี้จะลดเวลาการรวบรวมเนื่องจากส่วนหัวจะไม่ถูกรวบรวมทุกครั้งที่รวมอยู่ด้วย
การสอน ตัวอย่าง เอกสารผู้ใช้
แฮ็คมีความสุข!
การเรียกซ้ำมาโคร การโทรแบบเรียกซ้ำทำงานตามที่คาดไว้ โดยเฉพาะอย่างยิ่งในการใช้การเรียกซ้ำ Boost/Preprocessor เพียงแค่คัดลอกฟังก์ชั่นการเรียกซ้ำทั้งหมดจนถึงขีด จำกัด และแรงที่จะติดตามความลึกของการเรียกซ้ำหรือพึ่งพาการหักเงินในตัว เป็นล่าม Metalang99 ปราศจากข้อเสียดังกล่าว
เกือบจะเป็นไวยากรณ์เดียวกัน MetalAng99 ไม่ได้ดูเอเลี่ยนเกินไปเมื่อเปรียบเทียบกับคำสั่ง PP เนื่องจากไวยากรณ์แตกต่างกันอย่างไม่มีนัยสำคัญจากรหัส preprocessor ปกติ
แอปพลิเคชันบางส่วน แทนที่จะติดตามอาร์กิวเมนต์เสริมที่นี่และที่นั่น (เนื่องจากทำในการเพิ่ม/ประมวลผลล่วงหน้า) แอปพลิเคชันบางส่วนของ MetalAng99 ช่วยให้สามารถจับภาพสภาพแวดล้อมได้โดยใช้ค่าคงที่ก่อน นอกจากนั้นแอปพลิเคชันบางส่วนยังช่วยให้การใช้ metafunctions ซ้ำได้ดีขึ้น ดู ML99_const , ML99_compose ฯลฯ
การดีบักและการรายงานข้อผิดพลาด คุณสามารถแก้ไขข้อบกพร่องของมาโครได้อย่างสะดวกด้วย ML99_abort และรายงานข้อผิดพลาดที่ไม่สามารถกู้คืนได้ด้วย ML99_fatal ล่ามจะหยุดและทำเคล็ดลับทันที เพื่อความรู้ที่ดีที่สุดของเราไม่มีกรอบมาโครอื่น ๆ ที่ให้กลไกดังกล่าวสำหรับการดีบักและการรายงานข้อผิดพลาด
งานของฉันเกี่ยวกับ Poica ภาษาการเขียนโปรแกรมการวิจัยที่นำมาใช้กับ Boost/Preprocessor ทำให้ฉันไม่พอใจกับผลลัพธ์ ข้อ จำกัด พื้นฐานของ Boost/Preprocessor ทำให้ codebase ไม่สามารถแก้ไขได้ สิ่งเหล่านี้รวมถึงการโทรมาโครแบบเรียกซ้ำ (บล็อกโดย preprocessor) ซึ่งทำให้การดีบักฝันร้ายที่สมบูรณ์การขาดแอปพลิเคชันบางส่วนที่ทำให้บริบทผ่านไปอย่างน่าอึดอัดใจอย่างเต็มที่และทุกความผิดพลาดเดียว
เมื่อนั้นฉันก็เข้าใจว่าแทนที่จะเพิ่มคุณค่าให้กับตัวประมวลผลล่วงหน้าด้วยกลไกเฉพาะกิจต่าง ๆ เราควรสร้างกระบวนทัศน์ที่ชัดเจนซึ่งจะจัดโครงสร้าง metaprograms ด้วยความคิดเหล่านี้ในใจฉันเริ่มใช้ MetalAng99 ...
เรื่องสั้นสั้น ๆ ใช้เวลาครึ่งปีของการทำงานหนักเพื่อปล่อย V0.1.0 และเกือบหนึ่งปีเพื่อให้มีเสถียรภาพ ในฐานะที่เป็นแอปพลิเคชั่นในโลกแห่งความเป็นจริงของ MetalAng99 ฉันได้สร้าง DataType99 อย่างแน่นอนในรูปแบบเดียวกันกับที่ฉันต้องการให้เป็น: การใช้งานมีการประกาศอย่างมากไวยากรณ์นั้นดีและความหมายมีการกำหนดไว้อย่างดี
ในที่สุดฉันอยากจะบอกว่า MetalAng99 เป็นเพียงการแปลงไวยากรณ์เท่านั้นและไม่เกี่ยวกับงานที่ถูกผูกไว้กับ CPU ตัวประมวลผลล่วงหน้าช้าเกินไปและ จำกัด สำหรับการละเมิดเช่นนี้
ML99_assertIsTuple , ML99_assertIsNat เป็นต้นสำหรับข้อความวินิจฉัยที่ดีขึ้น## โทเค็นภายใน Metalang99 ที่สอดคล้องกับมาโครแทนที่จะเป็น ML99_cat หรือเพื่อนของมันเพราะข้อโต้แย้งจะยังคงขยายอย่างเต็มที่ML99_todo และเพื่อน ๆ เพื่อระบุฟังก์ชั่นที่ไม่ได้ใช้งาน ดู CONTRIBUTING.md .
ดู ARCHITECTURE.md
ดู idioms.md
ดู optimization_tips.md _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 )ไม่ว่าในกรณีใดคุณสามารถลองแก้จุดบกพร่อง metaprogram ของคุณซ้ำ ๆ จากประสบการณ์ของฉัน 95% ของข้อผิดพลาดที่เข้าใจได้ - Metalang99 ถูกสร้างขึ้นสำหรับมนุษย์ไม่ใช่สำหรับสัตว์ประหลาดมาโคร
ตอบ: ดูบท "การทดสอบการดีบักและการรายงานข้อผิดพลาด"
ตอบ: ฉันใช้รหัส VS สำหรับการพัฒนา มันช่วยให้คำแนะนำแบบป๊อปอัพของการสร้างที่สร้างขึ้นมาโคร แต่แน่นอนว่ามันไม่รองรับการเน้นไวยากรณ์มาโคร
ตอบ: ในการเรียกใช้เกณฑ์มาตรฐานให้ดำเนินการ ./scripts/bench.sh จากไดเรกทอรีราก
A:
ตอบ: ดูโพสต์บล็อก "อะไรคือจุดของตัวประมวลผล C จริง ๆ แล้วเหรอ?"
ตอบ: ตัวประมวลผล preprocessor C/C ++ มีความสามารถในการวนซ้ำได้ถึงขีด จำกัด ที่แน่นอนเท่านั้น สำหรับ MetalAng99 ขีด จำกัด นี้ถูกกำหนดในแง่ของขั้นตอนการลดลง: เมื่อขั้นตอนการลดจำนวนคงที่คงที่ metaprogram ของคุณจะไม่สามารถดำเนินการได้อีกต่อไป
ตอบ: MetalAng99 มีการกำหนดเป้าหมายเป็นหลักที่ Pure C และ C ขาดแม่แบบ แต่อย่างไรก็ตามคุณสามารถค้นหาการโต้แย้งสำหรับ C ++ ได้ที่เว็บไซต์ของ Boost/Preprocessor
ตอบ: ฉันต่อต้านส่วนหัวที่รวมกันเนื่องจากภาระกับการอัปเดต แต่คุณสามารถเพิ่ม MetalAng99 เป็น submodule Git และอัปเดตด้วย git submodule update --remote
A: C99/C ++ 11 ขึ้นไป
ตอบ: เป็นที่รู้จักกันในการทำงานของ MetalAng99