# This file assumes that the output of the generator will be placed # within a module or a class. However, the module/class requires a # `type` method, which takes a terminal and gives its type, as a # symbol. These types should line up with the terminals that were # defined in the original grammar. # The actions to take during parsing. In every state, there are a # set of acceptable peek tokens; this table tells the parser what # to do on each acceptable peek token. The possible actions include # `:accept`, `:reduce`, and `:state`; `:accept` means to accept the # input and return the value of the pasing. `:reduce` means to # reduce the top of the stack into a given nonterminal. `:state` # means to transition to another state. # # @return [Array)>>] ACTION_TABLE = <%= generate_action_table %>.freeze # > # A list of all of the productions. Only includes the left-hand side, # the number of tokens on the right-hand side, and the block to call # on reduction. # # @return [Array>] PRODUCTIONS = <%= generate_productions_list %>.freeze # > # Runs the parser. # # @param input [Array] the input to run the parser over. # @return [Object] the result of the accept. def parse(input) stack = [] stack.push([nil, 0]) input = input.dup last = nil until stack.empty? do peek_token = if input.empty? :"$" else type(input.first) end action = ACTION_TABLE[stack.last.last].fetch(peek_token) case action.first when :accept production = PRODUCTIONS[action.last] last = stack.pop(production[1]).first.first stack.pop when :reduce production = PRODUCTIONS[action.last] removing = stack.pop(production[1]) value = production[2].call(*removing.map(&:first)) goto = ACTION_TABLE[stack.last.last][production[0]] stack.push([value, goto.last]) when :state stack.push([input.shift, action.last]) else raise end end last end