📄 lr_parser.java
字号:
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Fetch an action from the action table. The table is broken up into * rows, one per state (rows are indexed directly by state number). * Within each row, a list of index, value pairs are given (as sequential * entries in the table), and the list is terminated by a default entry * (denoted with a symbol index of -1). To find the proper entry in a row * we do a linear or binary search (depending on the size of the row). * * @param state the state index of the action being accessed. * @param sym the symbol index of the action being accessed. */ protected final short get_action(int state, int sym) { short tag; int first, last, probe; short[] row = action_tab[state]; /* linear search if we are < 10 entries */ if (row.length < 20) for (probe = 0; probe < row.length; probe++) { /* is this entry labeled with our symbol or the default? */ tag = row[probe++]; if (tag == sym || tag == -1) { /* return the next entry */ return row[probe]; } } /* otherwise binary search */ else { first = 0; last = (row.length-1)/2 - 1; /* leave out trailing default entry */ while (first <= last) { probe = (first+last)/2; if (sym == row[probe*2]) return row[probe*2+1]; else if (sym > row[probe*2]) first = probe+1; else last = probe-1; } /* not found, use the default at the end */ return row[row.length-1]; } /* shouldn't happened, but if we run off the end we return the default (error == 0) */ return 0; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Fetch a state from the reduce-goto table. The table is broken up into * rows, one per state (rows are indexed directly by state number). * Within each row, a list of index, value pairs are given (as sequential * entries in the table), and the list is terminated by a default entry * (denoted with a symbol index of -1). To find the proper entry in a row * we do a linear search. * * @param state the state index of the entry being accessed. * @param sym the symbol index of the entry being accessed. */ protected final short get_reduce(int state, int sym) { short tag; short[] row = reduce_tab[state]; /* if we have a null row we go with the default */ if (row == null) return -1; for (int probe = 0; probe < row.length; probe++) { /* is this entry labeled with our symbol or the default? */ tag = row[probe++]; if (tag == sym || tag == -1) { /* return the next entry */ return row[probe]; } } /* if we run off the end we return the default (error == -1) */ return -1; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** This method provides the main parsing routine. It returns only when * done_parsing() has been called (typically because the parser has * accepted, or a fatal error has been reported). See the header * documentation for the class regarding how shift/reduce parsers operate * and how the various tables are used. */ public void parse() throws java.lang.Exception { /* the current action code */ int act; /* the symbol/stack element returned by a reduce */ symbol lhs_sym; /* information about production being reduced with */ short handle_size, lhs_sym_num; /* set up direct reference to tables to drive the parser */ production_tab = production_table(); action_tab = action_table(); reduce_tab = reduce_table(); /* initialize the action encapsulation object */ init_actions(); /* do user initialization */ user_init(); /* get the first token */ cur_token = scan(); /* push dummy symbol with start state to get us underway */ stack.push(new symbol(0, start_state())); tos = 0; /* continue until we are told to stop */ for (_done_parsing = false; !_done_parsing; ) { /* current state is always on the top of the stack */ /* look up action out of the current state with the current input */ act = get_action(((symbol)stack.peek()).parse_state, cur_token.sym); /* decode the action -- > 0 encodes shift */ if (act > 0) { /* shift to the encoded state by pushing it on the stack */ cur_token.parse_state = act-1; stack.push(cur_token); tos++; /* advance to the next token */ cur_token = scan(); } /* if its less than zero, then it encodes a reduce action */ else if (act < 0) { /* perform the action for the reduce */ lhs_sym = do_action((-act)-1, this, stack, tos); /* look up information about the production */ lhs_sym_num = production_tab[(-act)-1][0]; handle_size = production_tab[(-act)-1][1]; /* pop the handle off the stack */ for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; } /* look up the state to go to from the one popped back to */ act = get_reduce(((symbol)stack.peek()).parse_state, lhs_sym_num); /* shift to that state */ lhs_sym.parse_state = act; stack.push(lhs_sym); tos++; } /* finally if the entry is zero, we have an error */ else if (act == 0) { /* call user syntax error reporting routine */ syntax_error(cur_token); /* try to error recover */ if (!error_recovery(false)) { /* if that fails give up with a fatal syntax error */ unrecovered_syntax_error(cur_token); /* just in case that wasn't fatal enough, end parse */ done_parsing(); } } } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Write a debugging message to System.err for the debugging version * of the parser. * * @param mess the text of the debugging message. */ public void debug_message(String mess) { System.err.println(mess); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Dump the parse stack for debugging purposes. */ public void dump_stack() { if (stack == null) { debug_message("# Stack dump requested, but stack is null"); return; } debug_message("============ Parse Stack Dump ============"); /* dump the stack */ for (int i=0; i<stack.size(); i++) { debug_message("Symbol: " + ((symbol)stack.elementAt(i)).sym + " State: " + ((symbol)stack.elementAt(i)).parse_state); } debug_message("=========================================="); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Do debug output for a reduce. * * @param prod_num the production we are reducing with. * @param nt_num the index of the LHS non terminal. * @param rhs_size the size of the RHS. */ public void debug_reduce(int prod_num, int nt_num, int rhs_size) { debug_message("# Reduce with prod #" + prod_num + " [NT=" + nt_num + ", " + "SZ=" + rhs_size + "]"); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Do debug output for shift. * * @param shift_tkn the token being shifted onto the stack. */ public void debug_shift(token shift_tkn) { debug_message("# Shift under term #" + shift_tkn.sym + " to state #" + shift_tkn.parse_state); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Perform a parse with debugging output. This does exactly the * same things as parse(), except that it calls debug_shift() and * debug_reduce() when shift and reduce moves are taken by the parser * and produces various other debugging messages. */ public void debug_parse() throws java.lang.Exception { /* the current action code */ int act; /* the symbol/stack element returned by a reduce */ symbol lhs_sym; /* information about production being reduced with */ short handle_size, lhs_sym_num; /* set up direct reference to tables to drive the parser */ production_tab = production_table(); action_tab = action_table(); reduce_tab = reduce_table(); debug_message("# Initializing parser"); /* initialize the action encapsulation object */ init_actions(); /* do user initialization */ user_init(); /* the current token */ cur_token = scan(); debug_message("# Current token is #" + cur_token.sym); /* push dummy symbol with start state to get us underway */ stack.push(new symbol(0, start_state())); tos = 0; /* continue until we are told to stop */ for (_done_parsing = false; !_done_parsing; ) { /* current state is always on the top of the stack */ /* look up action out of the current state with the current input */ act = get_action(((symbol)stack.peek()).parse_state, cur_token.sym); /* decode the action -- > 0 encodes shift */ if (act > 0) { /* shift to the encoded state by pushing it on the stack */ cur_token.parse_state = act-1; debug_shift(cur_token); stack.push(cur_token); tos++; /* advance to the next token */ cur_token = scan(); debug_message("# Current token is #" + cur_token.sym); } /* if its less than zero, then it encodes a reduce action */ else if (act < 0) { /* perform the action for the reduce */ lhs_sym = do_action((-act)-1, this, stack, tos); /* look up information about the production */ lhs_sym_num = production_tab[(-act)-1][0]; handle_size = production_tab[(-act)-1][1]; debug_reduce((-act)-1, lhs_sym_num, handle_size); /* pop the handle off the stack */ for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; } /* look up the state to go to from the one popped back to */ act = get_reduce(((symbol)stack.peek()).parse_state, lhs_sym_num); /* shift to that state */ lhs_sym.parse_state = act; stack.push(lhs_sym); tos++; debug_message("# Goto state #" + act); } /* finally if the entry is zero, we have an error */ else if (act == 0) { /* call user syntax error reporting routine */ syntax_error(cur_token); /* try to error recover */ if (!error_recovery(true)) { /* if that fails give up with a fatal syntax error */ unrecovered_syntax_error(cur_token); /* just in case that wasn't fatal enough, end parse */ done_parsing(); } } } } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /* Error recovery code */ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Attempt to recover from a syntax error. This returns false if recovery * fails, true if it succeeds. Recovery happens in 4 steps. First we * pop the parse stack down to a point at which we have a shift out * of the top-most state on the error symbol. This represents the * initial error recovery configuration. If no such configuration is * found, then we fail. Next a small number of "lookahead" or "parse * ahead" tokens are read into a buffer. The size of this buffer is * determined by error_sync_size() and determines how many tokens beyond * the error must be matched to consider the recovery a success. Next,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -