ATOKダイレクト数式計算プラグインのソースコード

それなりに使えるレベルになったのでアップしてみた。
セットアップツールで公開しようかと思ったのだけど、はてなってzipファイルはアップロードできないようなのでソースコードを公開。

calc.y

class Calcp
  prechigh
    nonassoc UMINUS
    right '^'
    left '*' '/'
    left '+' '-'
    right '='
  preclow
rule
  target: exp
        | /* none */ { result = 0 }

  exp: exp '+' exp { result += val[2] }
     | exp '-' exp { result -= val[2] }
     | exp '*' exp { result *= val[2] }
     | exp '/' exp { result /= val[2] }
     | exp '^' exp { result **= val[2] }
     | '(' exp ')' { result = val[1] }
     | '-' NUMBER  =UMINUS { result = -val[1] }
     | NUMBER
     |  exp '='
end

これはRaccでコンパイルしてcalc.rbファイルに。


calc_plugin.rb

$KCODE = "UTF-8"
require 'jcode'
require File.dirname(__FILE__) + '\calc.rb'


### 字句解析部

class Calcp
  def parse(str)
    @q = []
    until str.empty?
      case str
      when /\A\s+/
        when /\A(\d|\.)+/
          @q.push [:NUMBER, $&.to_f]
        when /\A.|\n/o
          s = $&
          @q.push [s, s]
        end
        str = $'
      end
      @q.push [false, '$end']
      do_parse
    end
  def next_token
    @q.shift
  end
end

module Atok_plugin

  def run_process( a_request_data )
    result_data = Hash.new
    parser = Calcp.new
    result = 0
    result_str = String.new
    
    begin
      result = parser.parse(toHankaku( a_request_data[ 'composition_string' ] ))
      rescue ParseError
      result_str = "Error!"
    end

    if result % 1 == 0
      result = result.to_i
    end
    
    if result_str.empty?
      result_str = result.to_s
    end
	    
    equal = ""
    if nil == a_request_data[ 'composition_string' ].rindex(/["=="]/)
      equal = "="
    end
	    
    candidate_array = Array.new
    candidate_array.push( { 'hyoki' => toZenkaku(result_str)} )
    candidate_array.push( { 'hyoki' => "#{toZenkaku(a_request_data[ 'composition_string' ])}#{toZenkaku(equal)}#{toZenkaku(result_str)}" })
    candidate_array.push( { 'hyoki' => toHankaku(result_str)} )
    candidate_array.push( { 'hyoki' => "#{toHankaku(a_request_data[ 'composition_string' ])}#{equal}#{toHankaku(result_str)}" })
	    
    result_data[ 'candidate' ] = candidate_array

    result_data
  end
end

def toHankaku(str)
    zenkakuMap = Hash.new{ |hash, key| key}
    zenkakuMap.update({
      "0"=>"0", "1"=>"1", "2"=>"2", "3"=>"3", "4"=>"4",
      "5"=>"5", "6"=>"6", "7"=>"7", "8"=>"8", "9"=>"9",
      "+"=>"+", "−"=>"-", "*"=>"*", "/"=>"/", "^"=>"^",
      "."=> ".", "("=> "(", ")"=> ")", " "=> " ", "="=>"="})

    result = String.new
    str.each_char { |char| result.concat(zenkakuMap[char]) }
    
    result
end

def toZenkaku(str)
    hankakuMap = Hash.new{ |hash, key| key}
    hankakuMap.update({
      "0"=>"0", "1"=>"1", "2"=>"2", "3"=>"3", "4"=>"4",
      "5"=>"5", "6"=>"6", "7"=>"7", "8"=>"8", "9"=>"9",
      "+"=>"+", "-"=>"−", "*"=>"*", "/"=>"/", "^"=>"^",
      "."=> ".", "("=> "(", ")"=> ")", " "=> " ", "="=>"="})

    result = String.new
    str.each_char { |char| result.concat(hankakuMap[char]) }
    
    result
end

こっちがプラグインとして登録しているファイル。
calc.rbのファイル名を変える場合は

require File.dirname(__FILE__) + '\calc.rb'

の行を適宜直す。

ATOKは通常の変換モードで数式を入力しようとすると全角になるので、全角の入力で使えるように考慮してみた。変換結果をF10で半角にできないっぽいので半角の候補も追加。これで一応使い物になるかなー。