# ------------------------------------------------------ # output.c import os MINSHORT = -32768 MAXTABLE = 32767 class OutputBase: def __init__(self, bison): # By copying the dictionary we ensure no mixing to data # between different output methods self.__dict__.update(vars(bison).copy()) return def fatal(self, msg): banner = self.options.get('input', self.program_name) raise SystemExit('%s: fatal error: %s\n' % (banner, msg)) def output(self, outfile): self.output_token_defines(outfile.write) self.output_token_translations(outfile.write) self.output_gram(outfile.write) self.output_rule_data(outfile.write) self.output_actions(outfile.write) self.output_defines(outfile.write) return def output_token_defines(self, write): raise NotImplementedError('must override') def output_token_translations(self, write): raise NotImplementedError('must override') def output_gram(self, write): raise NotImplementedError('must override') def output_rule_data(self, write): raise NotImplementedError('must override') def output_actions(self, write): """ compute and output yydefact, yydefgoto, yypact, yypgoto, yytable and yycheck. """ self.nvectors = self.nstates + self.nvars self.froms = [None]*self.nvectors # list of lists self.tos = [None]*self.nvectors # list of lists self.tally = [0]*self.nvectors self.width = [0]*self.nvectors self.token_actions(write) self.goto_actions(write) self.sort_actions() self.pack_table() self.output_base(write) self.output_table(write) self.output_check(write) return # Helper function for token_actions() def action_row(self, state): """ Decide what to do for each type of token if seen as the lookahead token in specified state. The value returned is used as the default action (yydefact) for the state. In addition, actrow is filled with what to do for each kind of token, index by symbol number, with zero meaning do the default action. The value MINSHORT, a very negative number, means this situation is an error. The parser recognizes this value specially. This is where conflicts are resolved. The loop over lookahead rules considered lower-numbered rules last, and the last rule considered that likes a token gets to handle it. """ actrow = [0]*self.ntokens default_rule = 0 nodefault = 0 reduction = self.reduction_table[state] if reduction and reduction.rules: # loop over all the rules available here which require lookahead m = self.lookaheads[state] n = self.lookaheads[state + 1] for i in range(n-1, m-1, -1): rule = -self.LAruleno[i] # and find each token which the rule finds acceptable to come next for j in range(self.ntokens): # and record this rule as the rule to use if that token follows if self.LA[i][j]: actrow[j] = rule # now see which tokens are allowed for shifts in this state. # For them, record the shift as the thing to do. So shift is preferred to reduce. shift = self.shift_table[state] if shift: for shift_state in shift.shifts: if not shift_state: continue symbol = self.accessing_symbol[shift_state] if symbol >= self.ntokens: break # ISVAR(symbol) actrow[symbol] = shift_state # do not user any default reduction if there is a shift for error if symbol == self.error_token_number: nodefault = 1 # See which tokens are an explicit error in this state (due to nonassoc). # For them, record MINSHORT as the action. errors = self.err_table[state] if errors: for symbol in errors: actrow[symbol] = MINSHORT # now find the most common reduction and make it the default action for this state. if reduction and reduction.rules and not nodefault: if self.consistent[state]: default_rule = reduction.rules[0] else: max = 0 for i in range(m, n): rule = -self.LAruleno[i] count = reduce(lambda a, b, r=rule: a + (b == r), actrow, 0) if count > max: max = count default_rule = rule # actions which match the default are replaced with zero, # which means "use the default" if max: for j in range(self.ntokens): if actrow[j] == default_rule: actrow[j] = 0 default_rule = -default_rule # If have no default rule, the default is an error. # So replace any action which says "error" with "use default". if not default_rule: for j in range(self.ntokens): if actrow[j] == MINSHORT: actrow[j] = 0 # save_row(state) froms = [] tos = [] for i in range(self.ntokens): if actrow[i]: froms.append(i) tos.append(actrow[i]) self.froms[state] = froms self.tos[state] = tos if froms: self.tally[state] = len(froms) self.width[state] = froms[-1] - froms[0] + 1 return default_rule # Helper function for goto_actions() def default_goto(self, symbol): m = self.goto_map[symbol] n = self.goto_map[symbol + 1] state_count = [0]*self.nstates default_state = -1 if m != n: for i in range(m, n): state = self.to_state[i] state_count[state] = state_count[state] + 1 max = 0 for i in range(self.nstates): if state_count[i] > max: max = state_count[i] default_state = i # save_column(symbol, default_state) froms = [] tos = [] for i in range(m, n): if (self.to_state[i] != default_state): froms.append(self.from_state[i]) tos.append(self.to_state[i]) symno = symbol - self.ntokens + self.nstates count = len(froms) self.tally[symno] = count self.width[symno] = count and (froms[-1] - froms[0] + 1) self.froms[symno] = froms self.tos[symno] = tos return default_state # The next few functions decide how to pack and the # actions and gotos information into yytable def sort_actions(self): self.order = [0]*self.nvectors self.nentries = 0 for i in range(self.nvectors): if self.tally[i]: t = self.tally[i] w = self.width[i] j = self.nentries - 1 while (j >= 0 and self.width[self.order[j]] < w): j = j - 1 while (j >= 0 and self.width[self.order[j]] < w and self.tally[self.order[j]] < t): j = j - 1 for k in range(self.nentries - 1, j, -1): self.order[k + 1] = self.order[k] self.order[j + 1] = i self.nentries = self.nentries + 1 return def pack_table(self): self.base = [MINSHORT]*self.nvectors self.pos = [0]*self.nentries self.table = [0]*MAXTABLE self.check = [-1]*MAXTABLE self.lowzero = 0 self.high = 0 for i in range(self.nentries): state = self.matching_state(i) if state < 0: place = self.pack_vector(i) else: place = self.base[state] self.pos[i] = place self.base[self.order[i]] = place del self.froms del self.tos del self.pos def matching_state(self, vector): i = self.order[vector] if i >= self.nstates: return -1 t = self.tally[i] w = self.width[i] for prev in range(vector - 1, -1, -1): j = self.order[prev] if self.width[j] != w or self.tally[j] != t: return -1 for k in range(t): if (self.tos[j][k] != self.tos[i][k] or self.froms[j][k] != self.froms[i][k]): break else: return j return -1 def pack_vector(self, vector): i = self.order[vector] t = self.tally[i] if t == 0: self.fatal('pack_vector') froms = self.froms[i] tos = self.tos[i] for j in range(self.lowzero - froms[0], MAXTABLE): ok = 1 for k in range(t): loc = j + froms[k] if loc > MAXTABLE: self.fatal("maximum table size (%d) exceeded" % MAXTABLE) if self.table[loc] != 0: ok = 0 break else: for k in range(vector): if self.pos[k] == j: ok = 0 break if ok: for k in range(t): loc = j + froms[k] self.table[loc] = tos[k] self.check[loc] = froms[k] while self.table[self.lowzero] != 0: self.lowzero = self.lowzero + 1 if loc > self.high: self.high = loc return j self.fatal('pack_vector') return