ext/racc/cparse/cparse.c


DEFINITIONS

This source file includes following functions.
  1. id_to_value
  2. id_to_value
  3. value_to_id
  4. SYMBOL_P
  5. LONG2NUM
  6. num_to_long
  7. get_stack_tail
  8. cut_stack_tail
  9. D
  10. D
  11. racc_cparse
  12. racc_yyparse
  13. call_lexer
  14. lexer_iter
  15. lexer_i
  16. check_array
  17. check_hash
  18. check_num
  19. initialize_params
  20. extract_user_token
  21. parse_main
  22. shift
  23. reduce
  24. catch_iter
  25. reduce0
  26. Init_cparse


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