1/*
2
3    cparse.c -- Racc Runtime Core
4
5    Copyright (c) 1999-2006 Minero Aoki
6
7    This library is free software.
8    You can distribute/modify this program under the same terms of ruby.
9
10    $originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $
11
12*/
13
14#include "ruby/ruby.h"
15
16#ifndef FALSE
17#define FALSE 0
18#endif
19#ifndef TRUE
20#define TRUE 1
21#endif
22
23/* -----------------------------------------------------------------------
24                        Important Constants
25----------------------------------------------------------------------- */
26
27#define RACC_VERSION "1.4.5"
28
29#define DEFAULT_TOKEN -1
30#define ERROR_TOKEN    1
31#define FINAL_TOKEN    0
32
33#define vDEFAULT_TOKEN  INT2FIX(DEFAULT_TOKEN)
34#define vERROR_TOKEN    INT2FIX(ERROR_TOKEN)
35#define vFINAL_TOKEN    INT2FIX(FINAL_TOKEN)
36
37/* -----------------------------------------------------------------------
38                          File Local Variables
39----------------------------------------------------------------------- */
40
41static VALUE RaccBug;
42static VALUE CparseParams;
43
44static ID id_yydebug;
45static ID id_nexttoken;
46static ID id_onerror;
47static ID id_noreduce;
48static ID id_errstatus;
49
50static ID id_d_shift;
51static ID id_d_reduce;
52static ID id_d_accept;
53static ID id_d_read_token;
54static ID id_d_next_state;
55static ID id_d_e_pop;
56
57/* -----------------------------------------------------------------------
58                              Utils
59----------------------------------------------------------------------- */
60
61/* For backward compatibility */
62#ifndef ID2SYM
63# define ID2SYM(i) ULONG2NUM(i)
64#endif
65#ifndef SYM2ID
66#  define SYM2ID(v) ((ID)NUM2ULONG(v))
67#endif
68#ifndef SYMBOL_P
69#  define SYMBOL_P(v) FIXNUM_P(v)
70#endif
71#ifndef LONG2NUM
72#  define LONG2NUM(i) INT2NUM(i)
73#endif
74
75static ID value_to_id _((VALUE v));
76static inline long num_to_long _((VALUE n));
77
78static ID
79value_to_id(VALUE v)
80{
81    if (! SYMBOL_P(v)) {
82        rb_raise(rb_eTypeError, "not symbol");
83    }
84    return SYM2ID(v);
85}
86
87static inline long
88num_to_long(VALUE n)
89{
90    return NUM2LONG(n);
91}
92
93#define AREF(s, idx) \
94    ((0 <= idx && idx < RARRAY_LEN(s)) ? RARRAY_PTR(s)[idx] : Qnil)
95
96/* -----------------------------------------------------------------------
97                        Parser Stack Interfaces
98----------------------------------------------------------------------- */
99
100static VALUE get_stack_tail _((VALUE stack, long len));
101static void cut_stack_tail _((VALUE stack, long len));
102
103static VALUE
104get_stack_tail(VALUE stack, long len)
105{
106    if (len < 0) return Qnil;  /* system error */
107    if (len > RARRAY_LEN(stack)) len = RARRAY_LEN(stack);
108    return rb_ary_new4(len, RARRAY_PTR(stack) + RARRAY_LEN(stack) - len);
109}
110
111static void
112cut_stack_tail(VALUE stack, long len)
113{
114    while (len > 0) {
115        rb_ary_pop(stack);
116        len--;
117    }
118}
119
120#define STACK_INIT_LEN 64
121#define NEW_STACK() rb_ary_new2(STACK_INIT_LEN)
122#define PUSH(s, i) rb_ary_store(s, RARRAY_LEN(s), i)
123#define POP(s) rb_ary_pop(s)
124#define LAST_I(s) \
125    ((RARRAY_LEN(s) > 0) ? RARRAY_PTR(s)[RARRAY_LEN(s) - 1] : Qnil)
126#define GET_TAIL(s, len) get_stack_tail(s, len)
127#define CUT_TAIL(s, len) cut_stack_tail(s, len)
128
129/* -----------------------------------------------------------------------
130                       struct cparse_params
131----------------------------------------------------------------------- */
132
133struct cparse_params {
134    VALUE value_v;         /* VALUE version of this struct */
135
136    VALUE parser;          /* parser object */
137
138    int   lex_is_iterator;
139    VALUE lexer;           /* scanner object */
140    ID    lexmid;          /* name of scanner method (must be an iterator) */
141
142    /* State transition tables (immutable)
143       Data structure is from Dragon Book 4.9 */
144    /* action table */
145    VALUE action_table;
146    VALUE action_check;
147    VALUE action_default;
148    VALUE action_pointer;
149    /* goto table */
150    VALUE goto_table;
151    VALUE goto_check;
152    VALUE goto_default;
153    VALUE goto_pointer;
154
155    long  nt_base;         /* NonTerminal BASE index */
156    VALUE reduce_table;    /* reduce data table */
157    VALUE token_table;     /* token conversion table */
158
159    /* parser stacks and parameters */
160    VALUE state;
161    long curstate;
162    VALUE vstack;
163    VALUE tstack;
164    VALUE t;
165    long shift_n;
166    long reduce_n;
167    long ruleno;
168
169    long errstatus;         /* nonzero in error recovering mode */
170    long nerr;              /* number of error */
171
172    int use_result_var;
173
174    VALUE retval;           /* return value of parser routine */
175    long fin;               /* parse result status */
176#define CP_FIN_ACCEPT  1
177#define CP_FIN_EOT     2
178#define CP_FIN_CANTPOP 3
179
180    int debug;              /* user level debug */
181    int sys_debug;          /* system level debug */
182
183    long i;                 /* table index */
184};
185
186/* -----------------------------------------------------------------------
187                        Parser Main Routines
188----------------------------------------------------------------------- */
189
190static VALUE racc_cparse _((VALUE parser, VALUE arg, VALUE sysdebug));
191static VALUE racc_yyparse _((VALUE parser, VALUE lexer, VALUE lexmid,
192                             VALUE arg, VALUE sysdebug));
193
194static void call_lexer _((struct cparse_params *v));
195static VALUE lexer_i _((VALUE block_args, VALUE data, VALUE self));
196
197static VALUE assert_array _((VALUE a));
198static long assert_integer _((VALUE n));
199static VALUE assert_hash _((VALUE h));
200static VALUE initialize_params _((VALUE vparams, VALUE parser, VALUE arg,
201                                 VALUE lexer, VALUE lexmid));
202static void cparse_params_mark _((void *ptr));
203
204static void parse_main _((struct cparse_params *v,
205                         VALUE tok, VALUE val, int resume));
206static void extract_user_token _((struct cparse_params *v,
207                                  VALUE block_args, VALUE *tok, VALUE *val));
208static void shift _((struct cparse_params* v, long act, VALUE tok, VALUE val));
209static int reduce _((struct cparse_params* v, long act));
210static VALUE reduce0 _((VALUE block_args, VALUE data, VALUE self));
211
212#ifdef DEBUG
213# define D_puts(msg)        if (v->sys_debug) puts(msg)
214# define D_printf(fmt,arg)  if (v->sys_debug) printf(fmt,arg)
215#else
216# define D_puts(msg)
217# define D_printf(fmt,arg)
218#endif
219
220static VALUE
221racc_cparse(VALUE parser, VALUE arg, VALUE sysdebug)
222{
223    volatile VALUE vparams;
224    struct cparse_params *v;
225
226    vparams = Data_Make_Struct(CparseParams, struct cparse_params,
227                               cparse_params_mark, -1, v);
228    D_puts("starting cparse");
229    v->sys_debug = RTEST(sysdebug);
230    vparams = initialize_params(vparams, parser, arg, Qnil, Qnil);
231    v->lex_is_iterator = FALSE;
232    parse_main(v, Qnil, Qnil, 0);
233
234    return v->retval;
235}
236
237static VALUE
238racc_yyparse(VALUE parser, VALUE lexer, VALUE lexmid, VALUE arg, VALUE sysdebug)
239{
240    volatile VALUE vparams;
241    struct cparse_params *v;
242
243    vparams = Data_Make_Struct(CparseParams, struct cparse_params,
244                               cparse_params_mark, -1, v);
245    v->sys_debug = RTEST(sysdebug);
246    D_puts("start C yyparse");
247    vparams = initialize_params(vparams, parser, arg, lexer, lexmid);
248    v->lex_is_iterator = TRUE;
249    D_puts("params initialized");
250    parse_main(v, Qnil, Qnil, 0);
251    call_lexer(v);
252    if (!v->fin) {
253        rb_raise(rb_eArgError, "%s() is finished before EndOfToken",
254                 rb_id2name(v->lexmid));
255    }
256
257    return v->retval;
258}
259
260#ifdef HAVE_RB_BLOCK_CALL
261static void
262call_lexer(struct cparse_params *v)
263{
264    rb_block_call(v->lexer, v->lexmid, 0, NULL, lexer_i, v->value_v);
265}
266#else
267static VALUE
268lexer_iter(VALUE data)
269{
270    struct cparse_params *v;
271
272    Data_Get_Struct(data, struct cparse_params, v);
273    rb_funcall(v->lexer, v->lexmid, 0);
274    return Qnil;
275}
276
277static void
278call_lexer(struct cparse_params *v)
279{
280    rb_iterate(lexer_iter, v->value_v, lexer_i, v->value_v);
281}
282#endif
283
284static VALUE
285lexer_i(VALUE block_args, VALUE data, VALUE self)
286{
287    struct cparse_params *v;
288    VALUE tok, val;
289
290    Data_Get_Struct(data, struct cparse_params, v);
291    if (v->fin)
292        rb_raise(rb_eArgError, "extra token after EndOfToken");
293    extract_user_token(v, block_args, &tok, &val);
294    parse_main(v, tok, val, 1);
295    if (v->fin && v->fin != CP_FIN_ACCEPT)
296       rb_iter_break();
297    return Qnil;
298}
299
300static VALUE
301assert_array(VALUE a)
302{
303    Check_Type(a, T_ARRAY);
304    return a;
305}
306
307static VALUE
308assert_hash(VALUE h)
309{
310    Check_Type(h, T_HASH);
311    return h;
312}
313
314static long
315assert_integer(VALUE n)
316{
317    return NUM2LONG(n);
318}
319
320static VALUE
321initialize_params(VALUE vparams, VALUE parser, VALUE arg, VALUE lexer, VALUE lexmid)
322{
323    struct cparse_params *v;
324
325    Data_Get_Struct(vparams, struct cparse_params, v);
326    v->value_v = vparams;
327    v->parser = parser;
328    v->lexer = lexer;
329    if (! NIL_P(lexmid))
330        v->lexmid = value_to_id(lexmid);
331
332    v->debug = RTEST(rb_ivar_get(parser, id_yydebug));
333
334    Check_Type(arg, T_ARRAY);
335    if (!(13 <= RARRAY_LEN(arg) && RARRAY_LEN(arg) <= 14))
336        rb_raise(RaccBug, "[Racc Bug] wrong arg.size %ld", RARRAY_LEN(arg));
337    v->action_table   = assert_array  (RARRAY_PTR(arg)[ 0]);
338    v->action_check   = assert_array  (RARRAY_PTR(arg)[ 1]);
339    v->action_default = assert_array  (RARRAY_PTR(arg)[ 2]);
340    v->action_pointer = assert_array  (RARRAY_PTR(arg)[ 3]);
341    v->goto_table     = assert_array  (RARRAY_PTR(arg)[ 4]);
342    v->goto_check     = assert_array  (RARRAY_PTR(arg)[ 5]);
343    v->goto_default   = assert_array  (RARRAY_PTR(arg)[ 6]);
344    v->goto_pointer   = assert_array  (RARRAY_PTR(arg)[ 7]);
345    v->nt_base        = assert_integer(RARRAY_PTR(arg)[ 8]);
346    v->reduce_table   = assert_array  (RARRAY_PTR(arg)[ 9]);
347    v->token_table    = assert_hash   (RARRAY_PTR(arg)[10]);
348    v->shift_n        = assert_integer(RARRAY_PTR(arg)[11]);
349    v->reduce_n       = assert_integer(RARRAY_PTR(arg)[12]);
350    if (RARRAY_LEN(arg) > 13) {
351        v->use_result_var = RTEST(RARRAY_PTR(arg)[13]);
352    }
353    else {
354        v->use_result_var = TRUE;
355    }
356
357    v->tstack = v->debug ? NEW_STACK() : Qnil;
358    v->vstack = NEW_STACK();
359    v->state = NEW_STACK();
360    v->curstate = 0;
361    PUSH(v->state, INT2FIX(0));
362    v->t = INT2FIX(FINAL_TOKEN + 1);   /* must not init to FINAL_TOKEN */
363    v->nerr = 0;
364    v->errstatus = 0;
365    rb_ivar_set(parser, id_errstatus, LONG2NUM(v->errstatus));
366
367    v->retval = Qnil;
368    v->fin = 0;
369
370    v->lex_is_iterator = FALSE;
371
372    rb_iv_set(parser, "@vstack", v->vstack);
373    if (v->debug) {
374        rb_iv_set(parser, "@tstack", v->tstack);
375    }
376    else {
377        rb_iv_set(parser, "@tstack", Qnil);
378    }
379
380    return vparams;
381}
382
383static void
384cparse_params_mark(void *ptr)
385{
386    struct cparse_params *v = (struct cparse_params*)ptr;
387
388    rb_gc_mark(v->value_v);
389    rb_gc_mark(v->parser);
390    rb_gc_mark(v->lexer);
391    rb_gc_mark(v->action_table);
392    rb_gc_mark(v->action_check);
393    rb_gc_mark(v->action_default);
394    rb_gc_mark(v->action_pointer);
395    rb_gc_mark(v->goto_table);
396    rb_gc_mark(v->goto_check);
397    rb_gc_mark(v->goto_default);
398    rb_gc_mark(v->goto_pointer);
399    rb_gc_mark(v->reduce_table);
400    rb_gc_mark(v->token_table);
401    rb_gc_mark(v->state);
402    rb_gc_mark(v->vstack);
403    rb_gc_mark(v->tstack);
404    rb_gc_mark(v->t);
405    rb_gc_mark(v->retval);
406}
407
408static void
409extract_user_token(struct cparse_params *v, VALUE block_args,
410                   VALUE *tok, VALUE *val)
411{
412    if (NIL_P(block_args)) {
413        /* EOF */
414        *tok = Qfalse;
415        *val = rb_str_new("$", 1);
416        return;
417    }
418
419    if (!RB_TYPE_P(block_args, T_ARRAY)) {
420        rb_raise(rb_eTypeError,
421                 "%s() %s %"PRIsVALUE" (must be Array[2])",
422                 v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token",
423                 v->lex_is_iterator ? "yielded" : "returned",
424                 rb_obj_class(block_args));
425    }
426    if (RARRAY_LEN(block_args) != 2) {
427        rb_raise(rb_eArgError,
428                 "%s() %s wrong size of array (%ld for 2)",
429                 v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token",
430                 v->lex_is_iterator ? "yielded" : "returned",
431                 RARRAY_LEN(block_args));
432    }
433    *tok = AREF(block_args, 0);
434    *val = AREF(block_args, 1);
435}
436
437#define SHIFT(v,act,tok,val) shift(v,act,tok,val)
438#define REDUCE(v,act) do {\
439    switch (reduce(v,act)) {  \
440      case 0: /* normal */    \
441        break;                \
442      case 1: /* yyerror */   \
443        goto user_yyerror;    \
444      case 2: /* yyaccept */  \
445        D_puts("u accept");   \
446        goto accept;          \
447      default:                \
448        break;                \
449    }                         \
450} while (0)
451
452static void
453parse_main(struct cparse_params *v, VALUE tok, VALUE val, int resume)
454{
455    long i;              /* table index */
456    long act;            /* action type */
457    VALUE act_value;     /* action type, VALUE version */
458    int read_next = 1;   /* true if we need to read next token */
459    VALUE tmp;
460
461    if (resume)
462        goto resume;
463
464    while (1) {
465        D_puts("");
466        D_puts("---- enter new loop ----");
467        D_puts("");
468
469        D_printf("(act) k1=%ld\n", v->curstate);
470        tmp = AREF(v->action_pointer, v->curstate);
471        if (NIL_P(tmp)) goto notfound;
472        D_puts("(act) pointer[k1] ok");
473        i = NUM2LONG(tmp);
474
475        D_printf("read_next=%d\n", read_next);
476        if (read_next && (v->t != vFINAL_TOKEN)) {
477            if (v->lex_is_iterator) {
478                D_puts("resuming...");
479                if (v->fin) rb_raise(rb_eArgError, "token given after EOF");
480                v->i = i;  /* save i */
481                return;
482              resume:
483                D_puts("resumed");
484                i = v->i;  /* load i */
485            }
486            else {
487                D_puts("next_token");
488                tmp = rb_funcall(v->parser, id_nexttoken, 0);
489                extract_user_token(v, tmp, &tok, &val);
490            }
491            /* convert token */
492            v->t = rb_hash_aref(v->token_table, tok);
493            if (NIL_P(v->t)) {
494                v->t = vERROR_TOKEN;
495            }
496            D_printf("(act) t(k2)=%ld\n", NUM2LONG(v->t));
497            if (v->debug) {
498                rb_funcall(v->parser, id_d_read_token,
499                           3, v->t, tok, val);
500            }
501        }
502        read_next = 0;
503
504        i += NUM2LONG(v->t);
505        D_printf("(act) i=%ld\n", i);
506        if (i < 0) goto notfound;
507
508        act_value = AREF(v->action_table, i);
509        if (NIL_P(act_value)) goto notfound;
510        act = NUM2LONG(act_value);
511        D_printf("(act) table[i]=%ld\n", act);
512
513        tmp = AREF(v->action_check, i);
514        if (NIL_P(tmp)) goto notfound;
515        if (NUM2LONG(tmp) != v->curstate) goto notfound;
516        D_printf("(act) check[i]=%ld\n", NUM2LONG(tmp));
517
518        D_puts("(act) found");
519      act_fixed:
520        D_printf("act=%ld\n", act);
521        goto handle_act;
522
523      notfound:
524        D_puts("(act) not found: use default");
525        act_value = AREF(v->action_default, v->curstate);
526        act = NUM2LONG(act_value);
527        goto act_fixed;
528
529
530      handle_act:
531        if (act > 0 && act < v->shift_n) {
532            D_puts("shift");
533            if (v->errstatus > 0) {
534                v->errstatus--;
535                rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus));
536            }
537            SHIFT(v, act, v->t, val);
538            read_next = 1;
539        }
540        else if (act < 0 && act > -(v->reduce_n)) {
541            D_puts("reduce");
542            REDUCE(v, act);
543        }
544        else if (act == -(v->reduce_n)) {
545            goto error;
546          error_recovered:
547            ;   /* goto label requires stmt */
548        }
549        else if (act == v->shift_n) {
550            D_puts("accept");
551            goto accept;
552        }
553        else {
554            rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act);
555        }
556
557        if (v->debug) {
558            rb_funcall(v->parser, id_d_next_state,
559                       2, LONG2NUM(v->curstate), v->state);
560        }
561    }
562    /* not reach */
563
564
565  accept:
566    if (v->debug) rb_funcall(v->parser, id_d_accept, 0);
567    v->retval = RARRAY_PTR(v->vstack)[0];
568    v->fin = CP_FIN_ACCEPT;
569    return;
570
571
572  error:
573    D_printf("error detected, status=%ld\n", v->errstatus);
574    if (v->errstatus == 0) {
575        v->nerr++;
576        rb_funcall(v->parser, id_onerror,
577                   3, v->t, val, v->vstack);
578    }
579  user_yyerror:
580    if (v->errstatus == 3) {
581        if (v->t == vFINAL_TOKEN) {
582            v->retval = Qfalse;
583            v->fin = CP_FIN_EOT;
584            return;
585        }
586        read_next = 1;
587    }
588    v->errstatus = 3;
589    rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus));
590
591    /* check if we can shift/reduce error token */
592    D_printf("(err) k1=%ld\n", v->curstate);
593    D_printf("(err) k2=%d (error)\n", ERROR_TOKEN);
594    while (1) {
595        tmp = AREF(v->action_pointer, v->curstate);
596        if (NIL_P(tmp)) goto error_pop;
597        D_puts("(err) pointer[k1] ok");
598
599        i = NUM2LONG(tmp) + ERROR_TOKEN;
600        D_printf("(err) i=%ld\n", i);
601        if (i < 0) goto error_pop;
602
603        act_value = AREF(v->action_table, i);
604        if (NIL_P(act_value)) {
605            D_puts("(err) table[i] == nil");
606            goto error_pop;
607        }
608        act = NUM2LONG(act_value);
609        D_printf("(err) table[i]=%ld\n", act);
610
611        tmp = AREF(v->action_check, i);
612        if (NIL_P(tmp)) {
613            D_puts("(err) check[i] == nil");
614            goto error_pop;
615        }
616        if (NUM2LONG(tmp) != v->curstate) {
617            D_puts("(err) check[i] != k1");
618            goto error_pop;
619        }
620
621        D_puts("(err) found: can handle error token");
622        break;
623
624      error_pop:
625        D_puts("(err) act not found: can't handle error token; pop");
626
627        if (RARRAY_LEN(v->state) <= 1) {
628            v->retval = Qnil;
629            v->fin = CP_FIN_CANTPOP;
630            return;
631        }
632        POP(v->state);
633        POP(v->vstack);
634        v->curstate = num_to_long(LAST_I(v->state));
635        if (v->debug) {
636            POP(v->tstack);
637            rb_funcall(v->parser, id_d_e_pop,
638                       3, v->state, v->tstack, v->vstack);
639        }
640    }
641
642    /* shift/reduce error token */
643    if (act > 0 && act < v->shift_n) {
644        D_puts("e shift");
645        SHIFT(v, act, ERROR_TOKEN, val);
646    }
647    else if (act < 0 && act > -(v->reduce_n)) {
648        D_puts("e reduce");
649        REDUCE(v, act);
650    }
651    else if (act == v->shift_n) {
652        D_puts("e accept");
653        goto accept;
654    }
655    else {
656        rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act);
657    }
658    goto error_recovered;
659}
660
661static void
662shift(struct cparse_params *v, long act, VALUE tok, VALUE val)
663{
664    PUSH(v->vstack, val);
665    if (v->debug) {
666        PUSH(v->tstack, tok);
667        rb_funcall(v->parser, id_d_shift,
668                   3, tok, v->tstack, v->vstack);
669    }
670    v->curstate = act;
671    PUSH(v->state, LONG2NUM(v->curstate));
672}
673
674static int
675reduce(struct cparse_params *v, long act)
676{
677    VALUE code;
678    v->ruleno = -act * 3;
679    code = rb_catch("racc_jump", reduce0, v->value_v);
680    v->errstatus = num_to_long(rb_ivar_get(v->parser, id_errstatus));
681    return NUM2INT(code);
682}
683
684static VALUE
685reduce0(VALUE val, VALUE data, VALUE self)
686{
687    struct cparse_params *v;
688    VALUE reduce_to, reduce_len, method_id;
689    long len;
690    ID mid;
691    VALUE tmp, tmp_t = Qundef, tmp_v = Qundef;
692    long i, k1, k2;
693    VALUE goto_state;
694
695    Data_Get_Struct(data, struct cparse_params, v);
696    reduce_len = RARRAY_PTR(v->reduce_table)[v->ruleno];
697    reduce_to  = RARRAY_PTR(v->reduce_table)[v->ruleno+1];
698    method_id  = RARRAY_PTR(v->reduce_table)[v->ruleno+2];
699    len = NUM2LONG(reduce_len);
700    mid = value_to_id(method_id);
701
702    /* call action */
703    if (len == 0) {
704        tmp = Qnil;
705        if (mid != id_noreduce)
706            tmp_v = rb_ary_new();
707        if (v->debug)
708            tmp_t = rb_ary_new();
709    }
710    else {
711        if (mid != id_noreduce) {
712            tmp_v = GET_TAIL(v->vstack, len);
713            tmp = RARRAY_PTR(tmp_v)[0];
714        }
715        else {
716            tmp = RARRAY_PTR(v->vstack)[ RARRAY_LEN(v->vstack) - len ];
717        }
718        CUT_TAIL(v->vstack, len);
719        if (v->debug) {
720            tmp_t = GET_TAIL(v->tstack, len);
721            CUT_TAIL(v->tstack, len);
722        }
723        CUT_TAIL(v->state, len);
724    }
725    if (mid != id_noreduce) {
726        if (v->use_result_var) {
727            tmp = rb_funcall(v->parser, mid,
728                             3, tmp_v, v->vstack, tmp);
729        }
730        else {
731            tmp = rb_funcall(v->parser, mid,
732                             2, tmp_v, v->vstack);
733        }
734    }
735
736    /* then push result */
737    PUSH(v->vstack, tmp);
738    if (v->debug) {
739        PUSH(v->tstack, reduce_to);
740        rb_funcall(v->parser, id_d_reduce,
741                   4, tmp_t, reduce_to, v->tstack, v->vstack);
742    }
743
744    /* calculate transition state */
745    if (RARRAY_LEN(v->state) == 0)
746        rb_raise(RaccBug, "state stack unexpectedly empty");
747    k2 = num_to_long(LAST_I(v->state));
748    k1 = num_to_long(reduce_to) - v->nt_base;
749    D_printf("(goto) k1=%ld\n", k1);
750    D_printf("(goto) k2=%ld\n", k2);
751
752    tmp = AREF(v->goto_pointer, k1);
753    if (NIL_P(tmp)) goto notfound;
754
755    i = NUM2LONG(tmp) + k2;
756    D_printf("(goto) i=%ld\n", i);
757    if (i < 0) goto notfound;
758
759    goto_state = AREF(v->goto_table, i);
760    if (NIL_P(goto_state)) {
761        D_puts("(goto) table[i] == nil");
762        goto notfound;
763    }
764    D_printf("(goto) table[i]=%ld (goto_state)\n", NUM2LONG(goto_state));
765
766    tmp = AREF(v->goto_check, i);
767    if (NIL_P(tmp)) {
768        D_puts("(goto) check[i] == nil");
769        goto notfound;
770    }
771    if (tmp != LONG2NUM(k1)) {
772        D_puts("(goto) check[i] != table[i]");
773        goto notfound;
774    }
775    D_printf("(goto) check[i]=%ld\n", NUM2LONG(tmp));
776
777    D_puts("(goto) found");
778  transit:
779    PUSH(v->state, goto_state);
780    v->curstate = NUM2LONG(goto_state);
781    return INT2FIX(0);
782
783  notfound:
784    D_puts("(goto) not found: use default");
785    /* overwrite `goto-state' by default value */
786    goto_state = AREF(v->goto_default, k1);
787    goto transit;
788}
789
790/* -----------------------------------------------------------------------
791                          Ruby Interface
792----------------------------------------------------------------------- */
793
794void
795Init_cparse(void)
796{
797    VALUE Racc, Parser;
798    ID id_racc = rb_intern("Racc");
799
800    if (rb_const_defined(rb_cObject, id_racc)) {
801        Racc = rb_const_get(rb_cObject, id_racc);
802        Parser = rb_const_get_at(Racc, rb_intern("Parser"));
803    }
804    else {
805        Racc = rb_define_module("Racc");
806        Parser = rb_define_class_under(Racc, "Parser", rb_cObject);
807    }
808    rb_define_private_method(Parser, "_racc_do_parse_c", racc_cparse, 2);
809    rb_define_private_method(Parser, "_racc_yyparse_c", racc_yyparse, 4);
810    rb_define_const(Parser, "Racc_Runtime_Core_Version_C",
811                    rb_str_new2(RACC_VERSION));
812    rb_define_const(Parser, "Racc_Runtime_Core_Id_C",
813        rb_str_new2("$originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $"));
814
815    CparseParams = rb_define_class_under(Racc, "CparseParams", rb_cObject);
816
817    RaccBug = rb_eRuntimeError;
818
819    id_yydebug      = rb_intern("@yydebug");
820    id_nexttoken    = rb_intern("next_token");
821    id_onerror      = rb_intern("on_error");
822    id_noreduce     = rb_intern("_reduce_none");
823    id_errstatus    = rb_intern("@racc_error_status");
824
825    id_d_shift       = rb_intern("racc_shift");
826    id_d_reduce      = rb_intern("racc_reduce");
827    id_d_accept      = rb_intern("racc_accept");
828    id_d_read_token  = rb_intern("racc_read_token");
829    id_d_next_state  = rb_intern("racc_next_state");
830    id_d_e_pop       = rb_intern("racc_e_pop");
831}
832