# prime/grammar/grammar.rb
# $Id: grammar.rb,v 1.3 2005/03/07 07:51:33 komatsu Exp $
#
# Copyright (C) 2002 Hiroyuki Komatsu <komatsu@taiyaki.org>
#     All rights reserved.
#     This is free software with ABSOLUTELY NO WARRANTY.
#
# You can redistribute it and/or modify it under the terms of 
# the GNU General Public License version 2.
#

require 'prime/taiyaki'

class Grammar
  include Debug

  def initialize
    @debug_mode = false

    @part_alias  = Hash.new
    @conjugation = Hash.new
  end

  def loadfile (filename)
    ruby_object_file = filename + ".rbo"
    ancillaries = make_ancillaries(filename)
#     unless File::exist?(ruby_object_file) &&
# 	File::mtime(ruby_object_file) > File::mtime(filename) then
#       ancillaries = make_ancillaries (filename)

#       ruby_object = open(ruby_object_file, "w")
#       Marshal::dump(ancillaries, ruby_object)
#       ruby_object.close
#       debug_message ("Initialize the file of grammar.", false)
#     else
#       ruby_object = open(ruby_object_file, "r")
#       ancillaries = Marshal::load(ruby_object)
#       ruby_object.close
#       debug_message ("Load the ruby object of grammar.", false)
#     end

    ancillaries.each {|ancillary|
      expand_ancillary(ancillary)
    }
  end

  def lookup_katsuyou (parent, string, prefix="")
    debug_message("lookup_katsuyou('#{parent}', '#{string}', '#{prefix})'")
    if string == "" then # もっとしっかり実装しよう (parent の妥当性のチェック)
      return [[""]]
    end

#    results = [["", string]]
    results = []
    if @conjugation[parent] then
      @conjugation[parent].each {|ancillary|
	if string[0,ancillary.string.length] == ancillary.string then
	  next_string = string[ancillary.string.length..-1]
	  pos = (ancillary.name == "*" ? parent : ancillary.name)

          prefix_string = prefix + ancillary.string
#          prefix_string = prefix + " #{ancillary.string}(#{pos})"
	  if ancillary.terminal then
	    results.push([prefix_string, next_string, pos])
	  end
	  if next_string.length > 0 then
	    results = results + lookup_katsuyou(ancillary.name, next_string,
                                                prefix_string)
	  end
	end
      }
    end
    return results
  end

  private

  def expand_ancillary (ancillary)
    new_parents = ancillary.parents.map {|parent|
      expand_part_alias(parent)
    }
    new_parents = new_parents.flatten.uniq
    new_parents.each {|parent|
      @conjugation[parent] = [] unless @conjugation[parent]
      @conjugation[parent].push(ancillary)
    }
  end

  def expand_part_alias (part, conjugation = nil)
    (part, conjugation) = part.split(/::/) unless conjugation
    if @part_alias[part] then
      expansion = @part_alias[part].map {|aliased_part|
	expand_part_alias(aliased_part, conjugation)
      }
      return expansion.flatten <<
	part + (conjugation ? "::" + conjugation : "")
    else
      return part + (conjugation ? "::" + conjugation : "")
    end
  end

  def make_ancillaries (filename)
    ancillaries = []
    file = open(filename, "r")
    while line = file.gets do
      line.chomp!
      next if (line =~ /^\#/ or line =~ /^[ \t]*$/)
      while line =~ /\\ *$/ do
	line = line.gsub(/\\ *$/, " ") + file.readline.chomp
      end
      if line =~ /^=(.+)\t(.+)$/ then
	key = $~[1].strip
	values = $~[2].split(/,/).map{|value| value.strip}
	@part_alias[key] = [] unless @part_alias[key]
	@part_alias[key] = @part_alias[key] | values
      else
	ancillary = Ancillary.new(line)
	ancillaries.push(ancillary)
      end
    end
    return ancillaries
  end

  class Ancillary
    attr_accessor :name, :string, :terminal, :parents
    def initialize (line)
      (string, name, parent_line) = line.split(/\t/)
      parents = parent_line.split(/ *, */)
      @name = name
      if string =~ /\.$/ then
	@string   = string.chop
	@terminal = true
      else
	@string   = string
	@terminal = false
      end
      @parents = parents
    end
  end
end  
