質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.33%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Nim

Nimは、静的型付けプログラミング言語。Pythonの生産性でありながら、C言語のような高いパフォーマンスも持ち併せます。さらに自由度の高い言語で拡張性も重視されています。

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

Q&A

解決済

1回答

184閲覧

Nimのマクロで、emitプラグマでC言語を埋め込んだ関数を作ろうとしたが、トランスコンパイルされたコードでエラーが出て実行できない。

kiyoken

総合スコア18

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Nim

Nimは、静的型付けプログラミング言語。Pythonの生産性でありながら、C言語のような高いパフォーマンスも持ち併せます。さらに自由度の高い言語で拡張性も重視されています。

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

0グッド

0クリップ

投稿2025/02/13 11:58

実現したいこと

Nimは通常のforループだと、トランスコンパイルされたCのコードでwhiteループとして実行されるが、emitプラグマを使ってCのforループを用いると、通常よりも速く実行できることが分かった。
そこで、マクロを使ってそのforループの関数を作ろうとしている。

発生している問題・分からないこと

Nim本体のコンパイルは通るが、トランスコンパイルされたCのコードをgccでコンパイルする段階の時にエラーが出る。

エラーメッセージ

error

1C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:50:1: error: expected identifier or '(' before 'for' 2 50 | for(i=1;i<4;i++){ 3 | ^~~ 4C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:50:10: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token 5 50 | for(i=1;i<4;i++){ 6 | ^ 7C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:50:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before '++' token 8 50 | for(i=1;i<4;i++){ 9 | ^~ 10Error: execution of an external compiler program 'gcc.exe -c -w -fmax-errors=3 -mno-ms-bitfields -IC:\Users\kiyok\.choosenim\toolchains\nim-2.2.2\lib -IC:\Users\kiyok\source\repos\test -o C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c.o C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c' failed with exit code: 1

該当のソースコード

Nim

1import macros 2 3proc cfor_void():void= 4 var i:int 5 {.emit:""" 6 for(i=1;i<4;i++){ 7 """.} 8 echo i 9 {.emit:""" 10 }; 11 """.} 12 13cfor_void() 14 15dumpTree: 16 var i:int 17 {.emit:""" 18 for(i=1;i<4;i++){ 19 """.} 20 echo i 21 {.emit:""" 22 }; 23 """.} 24 25macro cfor():void = 26 result = nnkStmtList.newTree( 27 nnkVarSection.newTree( 28 nnkIdentDefs.newTree( 29 newIdentNode("i"), 30 newIdentNode("int"), 31 newEmptyNode() 32 ) 33 ), 34 nnkPragma.newTree( 35 nnkExprColonExpr.newTree( 36 newIdentNode("emit"), 37 newStrLitNode("for(i=1;i<4;i++){\n") 38 ) 39 ), 40 nnkCommand.newTree( 41 newIdentNode("echo"), 42 newIdentNode("i") 43 ), 44 nnkPragma.newTree( 45 nnkExprColonExpr.newTree( 46 newIdentNode("emit"), 47 newStrLitNode("};") 48 ) 49 ) 50 ) 51 52cfor()

C

1/* Generated by Nim Compiler v2.2.2 */ 2/* Compiled for: Windows, amd64, gcc */ 3/* Command for C compiler: 4 gcc.exe -c -w -fmax-errors=3 -mno-ms-bitfields -IC:\Users\kiyok\.choosenim\toolchains\nim-2.2.2\lib -IC:\Users\kiyok\source\repos\test -o C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c.o C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c */ 5#define NIM_INTBITS 64 6 7#include "nimbase.h" 8#undef LANGUAGE_C 9#undef MIPSEB 10#undef MIPSEL 11#undef PPC 12#undef R3000 13#undef R4000 14#undef i386 15#undef linux 16#undef mips 17#undef near 18#undef far 19#undef powerpc 20#undef unix 21#define nimfr_(proc, file) \ 22 TFrame FR_; \ 23 FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_); 24 25#define nimln_(n) \ 26 FR_.line = n; 27 28#define nimlf_(n, file) \ 29 FR_.line = n; FR_.filename = file; 30 31typedef struct NimStrPayload NimStrPayload; 32typedef struct NimStringV2 NimStringV2; 33struct NimStrPayload { 34 NI cap; 35 NIM_CHAR data[SEQ_DECL_SIZE]; 36}; 37struct NimStringV2 { 38 NI len; 39 NimStrPayload* p; 40}; 41typedef NimStringV2 tyArray__nHXaesL0DJZHyVS07ARPRA[1]; 42N_LIB_PRIVATE N_NIMCALL(void, cfor_void__macro95test_u2)(void); 43N_LIB_PRIVATE N_NIMCALL(NimStringV2, dollar___systemZdollars_u8)(NI x_p0); 44N_LIB_PRIVATE N_NIMCALL(void, echoBinSafe)(NimStringV2* args_p0, NI args_p0Len_0); 45N_LIB_PRIVATE N_NOCONV(void, deallocShared)(void* p_p0); 46static N_INLINE(NIM_BOOL*, nimErrorFlag)(void); 47static N_INLINE(void, nimFrame)(TFrame* s_p0); 48N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__system_u4678)(void); 49static N_INLINE(void, popFrame)(void); 50for(i=1;i<4;i++){ 51 52}; 53N_LIB_PRIVATE N_NIMCALL(void, nimTestErrorFlag)(void); 54N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatsexitprocsdotnim_Init000)(void); 55N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000)(void); 56N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_Init000)(void); 57N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000)(void); 58N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void); 59extern NIM_THREADVAR NIM_BOOL nimInErrorMode__system_u4460; 60extern NIM_THREADVAR TFrame* framePtr__system_u2692; 61N_LIB_PRIVATE NI i__macro95test_u27; 62static N_INLINE(NIM_BOOL*, nimErrorFlag)(void) { 63 NIM_BOOL* result; 64 result = (&nimInErrorMode__system_u4460); 65 return result; 66} 67static N_INLINE(void, nimFrame)(TFrame* s_p0) { 68 { 69 if (!(framePtr__system_u2692 == ((TFrame*) NIM_NIL))) goto LA3_; 70 (*s_p0).calldepth = ((NI16)0); 71 } 72 goto LA1_; 73LA3_: ; 74 { 75 (*s_p0).calldepth = (NI16)((*framePtr__system_u2692).calldepth + ((NI16)1)); 76 } 77LA1_: ; 78 (*s_p0).prev = framePtr__system_u2692; 79 framePtr__system_u2692 = s_p0; 80 { 81 if (!((*s_p0).calldepth == ((NI16)2000))) goto LA8_; 82 callDepthLimitReached__system_u4678(); 83 } 84LA8_: ; 85} 86static N_INLINE(void, popFrame)(void) { 87 framePtr__system_u2692 = (*framePtr__system_u2692).prev; 88} 89N_LIB_PRIVATE N_NIMCALL(void, cfor_void__macro95test_u2)(void) { 90 NimStringV2 colontmpD_; 91 NI i; 92 tyArray__nHXaesL0DJZHyVS07ARPRA T2_; 93NIM_BOOL* nimErr_; 94 nimfr_("cfor_void", "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); 95{nimErr_ = nimErrorFlag(); 96 colontmpD_.len = 0; colontmpD_.p = NIM_NIL; 97 i = (NI)0; 98 nimlf_(5, "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); for(i=1;i<4;i++){ 99 100 nimln_(8); colontmpD_ = dollar___systemZdollars_u8(i); 101 if (NIM_UNLIKELY(*nimErr_)) goto LA1_; 102 T2_[0] = colontmpD_; 103 echoBinSafe(T2_, 1); 104 nimln_(9); }; 105 106 { 107 LA1_:; 108 } 109 { 110 nimlf_(396, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\system.nim"); if (colontmpD_.p && !(colontmpD_.p->cap & NIM_STRLIT_FLAG)) { 111 deallocShared(colontmpD_.p); 112} 113 } 114 if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_; 115 }BeforeRet_: ; 116 popFrame(); 117} 118 119N_LIB_PRIVATE void PreMainInner(void) { 120 atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatsexitprocsdotnim_Init000(); 121 atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_Init000(); 122} 123 124N_LIB_PRIVATE int cmdCount; 125N_LIB_PRIVATE char** cmdLine; 126N_LIB_PRIVATE char** gEnv; 127N_LIB_PRIVATE void PreMain(void) { 128#if 0 129 void (*volatile inner)(void); 130 inner = PreMainInner; 131 atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000(); 132 atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000(); 133 (*inner)(); 134#else 135 atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000(); 136 atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000(); 137 PreMainInner(); 138#endif 139} 140 141N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) { 142 NimMainModule(); 143} 144 145N_CDECL(void, NimMain)(void) { 146#if 0 147 void (*volatile inner)(void); 148 PreMain(); 149 inner = NimMainInner; 150 (*inner)(); 151#else 152 PreMain(); 153 NimMainInner(); 154#endif 155} 156 157int main(int argc, char** args, char** env) { 158 cmdLine = args; 159 cmdCount = argc; 160 gEnv = env; 161 NimMain(); 162 return nim_program_result; 163} 164 165N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) { 166{ 167 NimStringV2 colontmpD_; 168 tyArray__nHXaesL0DJZHyVS07ARPRA T2_; 169NIM_BOOL* nimErr_; 170 nimfr_("macro_test", "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); 171nimErr_ = nimErrorFlag(); 172 colontmpD_.len = 0; colontmpD_.p = NIM_NIL; 173 nimlf_(13, "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); cfor_void__macro95test_u2(); 174 if (NIM_UNLIKELY(*nimErr_)) goto LA1_; 175 nimlf_(715, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\core\\macros.nim"); nimlf_(42, "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); colontmpD_ = dollar___systemZdollars_u8(i__macro95test_u27); 176 if (NIM_UNLIKELY(*nimErr_)) goto LA1_; 177 T2_[0] = colontmpD_; 178 echoBinSafe(T2_, 1); 179 { 180 LA1_:; 181 } 182 { 183 nimlf_(396, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\system.nim"); if (colontmpD_.p && !(colontmpD_.p->cap & NIM_STRLIT_FLAG)) { 184 deallocShared(colontmpD_.p); 185} 186 } 187 if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_; 188 BeforeRet_: ; 189 nimTestErrorFlag(); 190 popFrame(); 191} 192} 193 194

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

bingやgithubのCopilotでAST Nodeではなくquote do:を使ったマクロの実装方法も試したが、同じエラーが出た。

補足

このマクロのもとになっている関数であるcfor_void()は予想通りに動き、実行すると
1
2
3
と出力してくれる。
中身の処理をdumptreeで出力すると、
StmtList
VarSection
IdentDefs
Ident "i"
Ident "int"
Empty
Pragma
ExprColonExpr
Ident "emit"
TripleStrLit " for(i=1;i<4;i++){\n "
Command
Ident "echo"
Ident "i"
Pragma
ExprColonExpr
Ident "emit"
TripleStrLit " };\n "
となる。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

Stackoverflowにも質問を投げたところ、解決できました。
https://stackoverflow.com/questions/79444160/i-cant-make-a-macro-which-has-an-emit-pragma-on-nim-lang/

下のように、マクロでできた関数を別の関数でラップするとうまく実行できます。

Nim

1import macros 2 3macro cfor():void = 4 result = nnkStmtList.newTree( 5 nnkVarSection.newTree( 6 nnkIdentDefs.newTree( 7 newIdentNode("i"), 8 newIdentNode("int"), 9 newEmptyNode() 10 ) 11 ), 12 nnkPragma.newTree( 13 nnkExprColonExpr.newTree( 14 newIdentNode("emit"), 15 newStrLitNode("for(i=1;i<4;i++){\n") 16 ) 17 ), 18 nnkCommand.newTree( 19 newIdentNode("echo"), 20 newIdentNode("i") 21 ), 22 nnkPragma.newTree( 23 nnkExprColonExpr.newTree( 24 newIdentNode("emit"), 25 newStrLitNode("};") 26 ) 27 ) 28 ) 29 30proc execute():void= 31 cfor() 32 33execute()

投稿2025/02/17 13:29

kiyoken

総合スコア18

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.33%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問