Skip to content

Instantly share code, notes, and snippets.

@lnznt
Last active August 29, 2015 14:13
Show Gist options
  • Save lnznt/004a9c7844d55b9993b4 to your computer and use it in GitHub Desktop.
Save lnznt/004a9c7844d55b9993b4 to your computer and use it in GitHub Desktop.
Ruby: ミニ Prolog パーサ (改) ref: http://qiita.com/lnznt/items/016210e1121cc9219190
$ make
racc -g -o prolog_parser.rb prolog_parser.ry
:
: 実行例 (コマンドライン引数に渡す文字列には最後の「.」は含めません)
:
$ ruby prolog_parser.rb "abc"
:abc
$ ruby prolog_parser.rb "a(abc)"
{:a=>[:abc]}
$ ruby prolog_parser.rb "[1,2,3]"
[1, 2, 3]
$ ruby prolog_parser.rb "a(X) :- b(X),!"
{:":-"=>[{:a=>[{nil=>:X}]}, {:","=>[{:b=>[{nil=>:X}]}, :!]}]}
$ ruby prolog_parser.rb ",(,,,),,(,,,,,)"
{:","=>[{:","=>[:",", :","]}, {:","=>[:",", :",", :","]}]}
$ ruby prolog_parser.rb -v "a(abc)"
[:FUNCTOR, "a"]
[:ATOM, "abc"]
[")", ")"]
[".", "."]
nil
{:a=>[:abc]}
#
# $ ruby prolog_parser.rb [options]
#
# options are:
# -v トークンキューをダンプ出力する
# -d パーサデバッグコードを出力する
#
#
# パーサへのソースの指定の仕方 (同時に指定した場合、下の方が優先)
#
# parse メソッドに指定する方法
#
# parser.parse(term: str) .... 項(文字列、最後のピリオド(.)不要)
# parser.parse(line: str) .... 行(文字列、最後のピリオド(.)必要)
# parser.parse(file: path) ... ファイル名(文字列)
# parser.parse(io: io) ....... read により入力文字列を読み出せる IO
# parser.parse(enum: enum) ... next により入力文字列を読み出せる Enumerator
# parser.parse(reader: pr) ... call により入力文字列を取得できる Proc
# parser.parse(&pr) .......... (上と同じ)
#
# アクセサで指定する方法
#
# parser.term = str
# parser.line = str
# parser.file = path
# parser.io = io
# parser.enum = enum
# parser.reader = reader
#
# parser.parse
#
# ----
#
# parse の戻り値は、解析結果を出力する Enumerator である
#
# (I) ワンショット(解析結果を1回のみ取り出す)
#
# (例)
# pp result = parser.parse(line: str).first
#
# (II) イテレート(解析結果を繰り返し取り出す)
#
# (例)
# parser.parse(io: f).each {|result| pp result }
#
# pp results = parser.parse(io: f).entries
#
$ swipl -l server.pro -g 'create_server(3333).'
# サーバは起動したままになる...
$ ruby ../prolog_proxy.rb
"[assert(person(socrates))]"
"[assert(:-(mortal(_G61),person(_G61)))]"
"[mortal(socrates)]"
require 'socket'
module Prolog
class Proxy
attr_accessor :host, :port
def initialize(port:, host:'localhost', &block)
tap {|my| my.host, my.port = host, port }
instance_eval(&block) if block
end
# Prolog サーバのデータベースに節を問い合わせをする
def inquire(query, &conv)
conv ||= -> q { q }
TCPSocket.open(host, port) do |s|
###s.puts "#{conv.(query)}."
###s.gets
# SWI-Prolog 決め打ちでサーバが EUC-JP として処理する
s.puts "#{conv.(query.encode('EUC-JP'))}."
s.gets.encode('UTF-8', 'EUC-JP')
end
end
# Prolog サーバのデータベースに節を追加する
def insert(clause)
query =
clause =~ /-->/ ? "dcg_translate_rule((#{clause}),X),assert(X)" :
"assert((#{clause}))"
inquire(query)
end
end
end
if __FILE__ == $0
require 'pp'
require 'prolog_parser'
prolog = Prolog::Proxy.new port:3333
pp Prolog.to_prolog Prolog.to_ruby term:prolog.insert("person(socrates)")
pp Prolog.to_prolog Prolog.to_ruby term:prolog.insert("mortal(X) :- person(X)")
pp Prolog.to_prolog Prolog.to_ruby term:prolog.inquire("mortal(Who)")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment