[quickjs-devel] Re: using regular cpp with qjsc

  • From: Fabrice Bellard <fabrice@xxxxxxxxxxx>
  • To: quickjs-devel@xxxxxxxxxxxxx
  • Date: Mon, 9 Sep 2019 14:00:40 +0200

I agree the feature can be useful. We might add it in a future release. We are also thinking about adding an optional C like preprocessor in QuickJS (with at least #if/#endif and #define for simple identifiers).

Best regards,

Fabrice.

On 9/4/19 1:45 PM, Mario Gliewe wrote:

Hi,

while playing along with qjsc, i found it convinient to use the regular
c preprocessor when precompiling javascript to bytecode.

The problem was, that cpp would put out '#line' statements (actually: '#
nn "fname"') .

Here's a patch to make quickjs aware of these.. it will give usefull
filename/lino info in stacktraces.

caveats:

- it will leak some amount of memory for each '#line' sourceline, since
filename strings are never free()'d; i guess to avoid that, the
JSParseState's filename would have to be transformed into a JS_SYMBOL

- when having an #include inside a function, stacktraces will give wrong
filenames

greets

maG


--snip--

mag@mag-laptop:~/code/quickjs-2019-08-10$ git diff quickjs.c

diff --git a/quickjs.c b/quickjs.c
index 7bb20cb..6e14b37 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -19152,16 +19152,56 @@ static __exception int
js_parse_regexp(JSParseState *s)
  static __exception int next_token(JSParseState *s)
  {
      const uint8_t *p;
-    int c;
+    int c, lino;
      char buf[4096], *q;
      BOOL ident_has_escape;
     free_token(s, &s->token);
     p = s->last_ptr = s->buf_ptr;
-    s->got_lf = FALSE;
+
+
+    if (s->line_num>0)  // line_num==0 indicates start of parse stream
+        s->got_lf = FALSE;
+    else
+        s->line_num = 1;
+
      s->last_line_num = s->token.line_num;
   redo:
+    if (*p && s->got_lf) {
+        // parse cpp #line statements: '# nnn "fname"
+        // this might interfere with some valid ecma statements
(private names starting on new line),
+        // so we handle lines starting with whitspace as normal
javascript, and only consider '#' followed by whitespace
+        if (*p == '#' && (p[1]!=' ' && p[1] != '\t')) {
+            p++;
+            while (*p == '\t' || *p==' ')
+                p++;
+            if (*p>='0' && *p<='9') {
+                lino=0;
+                while (*p>='0' && *p<='9')
+                    lino = lino*10 + (*p++)-'0';
+                s->line_num = lino;
+                while (*p == '\t' || *p==' ')
+                    p++;
+                if (*p == '"') {
+                    p++;
+                    q=buf;
+                    while (*p && *p!='"' && *p!='\r' && *p != '\n') {
+                        if (q-buf < 4095)
+                            *q++=*p++;
+                    }
+                    *q=0;
+                    s->filename = js_strdup(s->ctx, buf);
+                }
+                while (* p && *p != '\r' && *p!='\n')
+                    p++;
+                if (*p == '\r') p++;
+                if (*p == '\n') p++;
+            }
+            goto redo;
+        }
+    }
+
      s->token.line_num = s->line_num;
      s->token.ptr = p;
      c = *p;
@@ -31084,9 +31124,10 @@ static void js_parse_init(JSContext *ctx,
JSParseState *s,
                            const char *filename)
  {
      memset(s, 0, sizeof(*s));
+    s->got_lf = TRUE;
      s->ctx = ctx;
      s->filename = filename;
-    s->line_num = 1;
+    s->line_num = 0;
      s->buf_ptr = (const uint8_t *)input;
      s->buf_end = s->buf_ptr + input_len;
      s->token.val = ' ';




Other related posts: