1. Steven! Ragnarök
  2. TopDowner

Source

TopDowner / top_downer.rb

class TopDowner
	def initialize grammar, token_types
		@grammar = grammar
		@token_types = token_types
		@r_cache = Hash.new
	end

	def parse string
		@enumerator = tokenize(string).each
		@tree = Hash.new
		recognize [:Program]
	end

	private
	## A Token Type Detector ##
	def detect(token)
		@token_types.each do |type, matcher|
			if token =~ matcher
				return { :token => token, :type => type }
			end
		end
		raise ArgumentError.new "Unknown token type for #{token}"
	end

	## String Tokenizer ##
	# Breaks up a string into an array of symbols.
	def tokenize string
		tokens = string.gsub(/[\n\t ]+/,' ').split(' ').map {|t| t.to_sym}
		tokens.map do |token|
			detect(token)
		end
	end

	# Returns all valid token types of the first terminal in a construct.
	def first construct
		#		return [Grammar.has_key? construct && first(Grammar[construct]) ||
			# construct].flatten
	end

	## Recognizer ##
	# Returns a symbol describing what is constructed by the token 
	# and lookahead. For a token :return and a lookahead :"4", it returns
	# :ReturnStatement. For a token :lparen and a lookahead :ident it would
	# return :Arglist.

	def recognize construct
		case construct
		# Array means nonliteral.
		when Array
			# check for meta-grammar
			return construct.map {|r| parse @grammar[r] || r}
		# Symbol means literal
		when Symbol
			tkn = @enumerator.next
			puts tkn
			if tkn[:type] == construct
				# Base step of recursion
				return tkn[:token]
			else
				raise ArgumentError.new "Got #{tkn}, expected #{recognizer}"
			end
		else raise ArgumentError.new "What the fuck?"
		end
	end
end