Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Tuesday, May 12, 2009

Cryptic infinite recursion in parse.y

When a single quote comes, parse.y will do:

case '\'':
  lex_strterm = NEW_STRTERM(str_squote, '\'', 0);
  return tSTRING_BEG;

This piece of codes is very same as a part of :'aaa'

NEW_STRTERM is a macro. It is a wrapper of a macro rb_node_newnode, which is a wrapper of a function node_newnode

#define NEW_STRTERM(func, term, paren) \
        rb_node_newnode(NODE_STRTERM, (func), (term) | ((paren) << (CHAR_BIT * 2)), 0)

#define rb_node_newnode(type, a1, a2, a3) node_newnode(parser, type, a1, a2, a3)

static NODE*
node_newnode(struct parser_params *parser, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
    NODE *n = (rb_node_newnode)(type, a0, a1, a2);
    nd_set_line(n, ruby_sourceline);
    return n;
}

The last function node_newnode calls rb_node_newnode, that is node_newnode itself, recursively.

Here is the node_newnode which macro is expanded:

static NODE*
node_newnode(struct parser_params *parser, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
    NODE *n = node_newnode(parser, type, a0, a1, a2);
    nd_set_line(n, ruby_sourceline);
    return n;
}

It's mysterious. node_newnode seems infinite recursion without any terminate conditions. Why does it work?

2 comments:

  1. A function type macro is not expanded in this case.
    I think it is a normal function call.
    The function rb_node_newnode is defined in node.h.

    ReplyDelete
  2. Thank you! I rak'd rb_node_newnode to find where is the definition. The perpetrator is gc.c!

    NODE*
    rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
    {
    NODE *n = (NODE*)rb_newobj();

    n->flags |= T_NODE;
    nd_set_type(n, type);

    n->u1.value = a0;
    n->u2.value = a1;
    n->u3.value = a2;

    return n;
    }

    ReplyDelete

Followers