I'm making a macro to use C's for-loop in Nim, because I noticed that C's for-loop is faster than Nim's for-loop.
During compilation it was passed to the nim compiler, but not to gcc. This is the code.
import macros
macro cfor():void =
result = nnkStmtList.newTree(
nnkVarSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("i"),
newIdentNode("int"),
newEmptyNode()
)
),
nnkPragma.newTree(
nnkExprColonExpr.newTree(
newIdentNode("emit"),
newStrLitNode("for(i=1;i<4;i++){\n")
)
),
nnkCommand.newTree(
newIdentNode("echo"),
newIdentNode("i")
),
nnkPragma.newTree(
nnkExprColonExpr.newTree(
newIdentNode("emit"),
newStrLitNode("};")
)
)
)
cfor()
And, this is the error message.
CC: macro_test.nim
C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:42:1: error: expected identifier or '(' before 'for'
42 | for(i=1;i<4;i++){
| ^~~
C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:42:10: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
42 | for(i=1;i<4;i++){
| ^
C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:42:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before '++' token
42 | for(i=1;i<4;i++){
| ^~
compilation terminated due to -fmax-errors=3.
Error: 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
This is generated C code.
/* Generated by Nim Compiler v2.2.2 */
/* Compiled for: Windows, amd64, gcc */
/* Command for C compiler:
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 */
#define NIM_INTBITS 64
#include "nimbase.h"
#undef LANGUAGE_C
#undef MIPSEB
#undef MIPSEL
#undef PPC
#undef R3000
#undef R4000
#undef i386
#undef linux
#undef mips
#undef near
#undef far
#undef powerpc
#undef unix
#define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
#define nimln_(n) \
FR_.line = n;
#define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
typedef struct NimStrPayload NimStrPayload;
typedef struct NimStringV2 NimStringV2;
struct NimStrPayload {
NI cap;
NIM_CHAR data[SEQ_DECL_SIZE];
};
struct NimStringV2 {
NI len;
NimStrPayload* p;
};
typedef NimStringV2 tyArray__nHXaesL0DJZHyVS07ARPRA[1];
for(i=1;i<4;i++){
N_LIB_PRIVATE N_NIMCALL(NimStringV2, dollar___systemZdollars_u8)(NI x_p0);
N_LIB_PRIVATE N_NIMCALL(void, echoBinSafe)(NimStringV2* args_p0, NI args_p0Len_0);
};
N_LIB_PRIVATE N_NOCONV(void, deallocShared)(void* p_p0);
static N_INLINE(NIM_BOOL*, nimErrorFlag)(void);
N_LIB_PRIVATE N_NIMCALL(void, nimTestErrorFlag)(void);
static N_INLINE(void, nimFrame)(TFrame* s_p0);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__system_u4678)(void);
static N_INLINE(void, popFrame)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatsexitprocsdotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
N_LIB_PRIVATE NI i__macro95test_u5;
extern NIM_THREADVAR NIM_BOOL nimInErrorMode__system_u4460;
extern NIM_THREADVAR TFrame* framePtr__system_u2692;
static N_INLINE(NIM_BOOL*, nimErrorFlag)(void) {
NIM_BOOL* result;
result = (&nimInErrorMode__system_u4460);
return result;
}
static N_INLINE(void, nimFrame)(TFrame* s_p0) {
{
if (!(framePtr__system_u2692 == ((TFrame*) NIM_NIL))) goto LA3_;
(*s_p0).calldepth = ((NI16)0);
}
goto LA1_;
LA3_: ;
{
(*s_p0).calldepth = (NI16)((*framePtr__system_u2692).calldepth + ((NI16)1));
}
LA1_: ;
(*s_p0).prev = framePtr__system_u2692;
framePtr__system_u2692 = s_p0;
{
if (!((*s_p0).calldepth == ((NI16)2000))) goto LA8_;
callDepthLimitReached__system_u4678();
}
LA8_: ;
}
static N_INLINE(void, popFrame)(void) {
framePtr__system_u2692 = (*framePtr__system_u2692).prev;
}
N_LIB_PRIVATE void PreMainInner(void) {
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatsexitprocsdotnim_Init000();
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_Init000();
}
N_LIB_PRIVATE int cmdCount;
N_LIB_PRIVATE char** cmdLine;
N_LIB_PRIVATE char** gEnv;
N_LIB_PRIVATE void PreMain(void) {
#if 0
void (*volatile inner)(void);
inner = PreMainInner;
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000();
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000();
(*inner)();
#else
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000();
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000();
PreMainInner();
#endif
}
N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {
NimMainModule();
}
N_CDECL(void, NimMain)(void) {
#if 0
void (*volatile inner)(void);
PreMain();
inner = NimMainInner;
(*inner)();
#else
PreMain();
NimMainInner();
#endif
}
int main(int argc, char** args, char** env) {
cmdLine = args;
cmdCount = argc;
gEnv = env;
NimMain();
return nim_program_result;
}
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
NimStringV2 colontmpD_;
tyArray__nHXaesL0DJZHyVS07ARPRA T2_;
NIM_BOOL* nimErr_;
nimfr_("macro_test", "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim");
nimErr_ = nimErrorFlag();
colontmpD_.len = 0; colontmpD_.p = NIM_NIL;
nimlf_(715, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\core\\macros.nim"); nimlf_(20, "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); colontmpD_ = dollar___systemZdollars_u8(i__macro95test_u5);
if (NIM_UNLIKELY(*nimErr_)) goto LA1_;
T2_[0] = colontmpD_;
echoBinSafe(T2_, 1);
{
LA1_:;
}
{
nimlf_(396, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\system.nim"); if (colontmpD_.p && !(colontmpD_.p->cap & NIM_STRLIT_FLAG)) {
deallocShared(colontmpD_.p);
}
}
if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;
BeforeRet_: ;
nimTestErrorFlag();
popFrame();
}
}
It confuses me that the original code works fine.
import macros
proc cfor_void():void=
var i:int
{.emit:"""
for(i=1;i<4;i++){
""".}
echo i
{.emit:"""
};
""".}
cfor_void()
dumpTree:
var i:int
{.emit:"""
for(i=1;i<4;i++){
""".}
echo i
{.emit:"""
};
""".}
#[output
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
Ident "emit"
TripleStrLit " };\n "
Hint: C:\Users\kiyok\source\repos\test\forloop_test.exe [Exec]
1
2
3
]#
How to fix this error? Or is there a better way to implement it?
I have asked bing and github copilot, but they cannot fix it.
I also have asked this on teratale, which is a Japanese question site, like stackoverflow. This is the url. But I don't have any answers yet.
I'm making a macro to use C's for-loop in Nim, because I noticed that C's for-loop is faster than Nim's for-loop.
During compilation it was passed to the nim compiler, but not to gcc. This is the code.
import macros
macro cfor():void =
result = nnkStmtList.newTree(
nnkVarSection.newTree(
nnkIdentDefs.newTree(
newIdentNode("i"),
newIdentNode("int"),
newEmptyNode()
)
),
nnkPragma.newTree(
nnkExprColonExpr.newTree(
newIdentNode("emit"),
newStrLitNode("for(i=1;i<4;i++){\n")
)
),
nnkCommand.newTree(
newIdentNode("echo"),
newIdentNode("i")
),
nnkPragma.newTree(
nnkExprColonExpr.newTree(
newIdentNode("emit"),
newStrLitNode("};")
)
)
)
cfor()
And, this is the error message.
CC: macro_test.nim
C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:42:1: error: expected identifier or '(' before 'for'
42 | for(i=1;i<4;i++){
| ^~~
C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:42:10: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
42 | for(i=1;i<4;i++){
| ^
C:\Users\kiyok\nimcache\macro_test_d\@mmacro_test.nim.c:42:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before '++' token
42 | for(i=1;i<4;i++){
| ^~
compilation terminated due to -fmax-errors=3.
Error: 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
This is generated C code.
/* Generated by Nim Compiler v2.2.2 */
/* Compiled for: Windows, amd64, gcc */
/* Command for C compiler:
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 */
#define NIM_INTBITS 64
#include "nimbase.h"
#undef LANGUAGE_C
#undef MIPSEB
#undef MIPSEL
#undef PPC
#undef R3000
#undef R4000
#undef i386
#undef linux
#undef mips
#undef near
#undef far
#undef powerpc
#undef unix
#define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
#define nimln_(n) \
FR_.line = n;
#define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
typedef struct NimStrPayload NimStrPayload;
typedef struct NimStringV2 NimStringV2;
struct NimStrPayload {
NI cap;
NIM_CHAR data[SEQ_DECL_SIZE];
};
struct NimStringV2 {
NI len;
NimStrPayload* p;
};
typedef NimStringV2 tyArray__nHXaesL0DJZHyVS07ARPRA[1];
for(i=1;i<4;i++){
N_LIB_PRIVATE N_NIMCALL(NimStringV2, dollar___systemZdollars_u8)(NI x_p0);
N_LIB_PRIVATE N_NIMCALL(void, echoBinSafe)(NimStringV2* args_p0, NI args_p0Len_0);
};
N_LIB_PRIVATE N_NOCONV(void, deallocShared)(void* p_p0);
static N_INLINE(NIM_BOOL*, nimErrorFlag)(void);
N_LIB_PRIVATE N_NIMCALL(void, nimTestErrorFlag)(void);
static N_INLINE(void, nimFrame)(TFrame* s_p0);
N_LIB_PRIVATE N_NOINLINE(void, callDepthLimitReached__system_u4678)(void);
static N_INLINE(void, popFrame)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatsexitprocsdotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
N_LIB_PRIVATE NI i__macro95test_u5;
extern NIM_THREADVAR NIM_BOOL nimInErrorMode__system_u4460;
extern NIM_THREADVAR TFrame* framePtr__system_u2692;
static N_INLINE(NIM_BOOL*, nimErrorFlag)(void) {
NIM_BOOL* result;
result = (&nimInErrorMode__system_u4460);
return result;
}
static N_INLINE(void, nimFrame)(TFrame* s_p0) {
{
if (!(framePtr__system_u2692 == ((TFrame*) NIM_NIL))) goto LA3_;
(*s_p0).calldepth = ((NI16)0);
}
goto LA1_;
LA3_: ;
{
(*s_p0).calldepth = (NI16)((*framePtr__system_u2692).calldepth + ((NI16)1));
}
LA1_: ;
(*s_p0).prev = framePtr__system_u2692;
framePtr__system_u2692 = s_p0;
{
if (!((*s_p0).calldepth == ((NI16)2000))) goto LA8_;
callDepthLimitReached__system_u4678();
}
LA8_: ;
}
static N_INLINE(void, popFrame)(void) {
framePtr__system_u2692 = (*framePtr__system_u2692).prev;
}
N_LIB_PRIVATE void PreMainInner(void) {
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatsexitprocsdotnim_Init000();
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_Init000();
}
N_LIB_PRIVATE int cmdCount;
N_LIB_PRIVATE char** cmdLine;
N_LIB_PRIVATE char** gEnv;
N_LIB_PRIVATE void PreMain(void) {
#if 0
void (*volatile inner)(void);
inner = PreMainInner;
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000();
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000();
(*inner)();
#else
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatsstdatssynciodotnim_DatInit000();
atmdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus2dot2dot2atslibatssystemdotnim_Init000();
PreMainInner();
#endif
}
N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {
NimMainModule();
}
N_CDECL(void, NimMain)(void) {
#if 0
void (*volatile inner)(void);
PreMain();
inner = NimMainInner;
(*inner)();
#else
PreMain();
NimMainInner();
#endif
}
int main(int argc, char** args, char** env) {
cmdLine = args;
cmdCount = argc;
gEnv = env;
NimMain();
return nim_program_result;
}
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
NimStringV2 colontmpD_;
tyArray__nHXaesL0DJZHyVS07ARPRA T2_;
NIM_BOOL* nimErr_;
nimfr_("macro_test", "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim");
nimErr_ = nimErrorFlag();
colontmpD_.len = 0; colontmpD_.p = NIM_NIL;
nimlf_(715, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\core\\macros.nim"); nimlf_(20, "C:\\Users\\kiyok\\source\\repos\\test\\macro_test.nim"); colontmpD_ = dollar___systemZdollars_u8(i__macro95test_u5);
if (NIM_UNLIKELY(*nimErr_)) goto LA1_;
T2_[0] = colontmpD_;
echoBinSafe(T2_, 1);
{
LA1_:;
}
{
nimlf_(396, "C:\\Users\\kiyok\\.choosenim\\toolchains\\nim-2.2.2\\lib\\system.nim"); if (colontmpD_.p && !(colontmpD_.p->cap & NIM_STRLIT_FLAG)) {
deallocShared(colontmpD_.p);
}
}
if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;
BeforeRet_: ;
nimTestErrorFlag();
popFrame();
}
}
It confuses me that the original code works fine.
import macros
proc cfor_void():void=
var i:int
{.emit:"""
for(i=1;i<4;i++){
""".}
echo i
{.emit:"""
};
""".}
cfor_void()
dumpTree:
var i:int
{.emit:"""
for(i=1;i<4;i++){
""".}
echo i
{.emit:"""
};
""".}
#[output
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
Ident "emit"
TripleStrLit " };\n "
Hint: C:\Users\kiyok\source\repos\test\forloop_test.exe [Exec]
1
2
3
]#
How to fix this error? Or is there a better way to implement it?
I have asked bing and github copilot, but they cannot fix it.
I also have asked this on teratale, which is a Japanese question site, like stackoverflow. This is the url. https://teratail/questions/t1mwjm31tw59km But I don't have any answers yet.
Share Improve this question asked Feb 17 at 0:05 kiyoken kiyokenkiyoken kiyoken 32 bronze badges New contributor kiyoken kiyoken is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.1 Answer
Reset to default 0Nim has a special case for emit
statements in the global scope. In order for types and includes to work they are moved outside the implicit main
function Nim generates. In order to fix this you can simply call your cfor
macro from within a function. e.g:
proc main() =
cfor()
main()
That being said I find myself doubting your assertion that C loops are faster than Nim loops. Generally Nims C output is optimized very well. You might be running into bounds checking which you can speed up significantly with -d:release
or even -d:danger
.