最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

I can't make a macro which has an emit pragma on Nim-lang - Stack Overflow

programmeradmin4浏览0评论

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.
Add a comment  | 

1 Answer 1

Reset to default 0

Nim 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.

发布评论

评论列表(0)

  1. 暂无评论