mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
210367ec88
which included commits to RCS files with non-trunk default branches. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@373 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1015 lines
21 KiB
Ruby
1015 lines
21 KiB
Ruby
#!/usr/local/bin/ruby
|
||
#
|
||
# rbc.rb -
|
||
# $Release Version: 0.8 $
|
||
# $Revision: 1.8 $
|
||
# $Date: 1998/03/11 05:43:00 $
|
||
# by Keiju ISHITSUKA(Nippon Rational Inc.)
|
||
#
|
||
# --
|
||
# Usage:
|
||
#
|
||
# rbc.rb [options] file_name opts
|
||
# options:
|
||
# -d debug mode (not recommended)
|
||
# -f does not read ~/.irbrc
|
||
# -m bc mode (rational/matrix calc)
|
||
# -r load-module same as `ruby -r'
|
||
# --inspect use inspect for result output
|
||
# (default for non-bc mode)
|
||
# --noinspect does not use inspect for result output
|
||
# --noreadline does not use readline library
|
||
# (default: try to use readline)
|
||
#
|
||
# additional private method (as function):
|
||
# exit, quit terminate the interpreter
|
||
# inspect_mode(sw = nil) toggle inspect mode
|
||
# trace_load(sw = nil) change trace mode for file loading using
|
||
# load/require. (default: trace-mode on)
|
||
#
|
||
require "e2mmap.rb"
|
||
|
||
$stdout.sync = TRUE
|
||
|
||
module BC_APPLICATION__
|
||
RCS_ID='-$Id: rbc.rb,v 1.8 1998/03/11 05:43:00 keiju Exp keiju $-'
|
||
|
||
extend Exception2MessageMapper
|
||
def_exception :UnrecognizedSwitch, "Unrecognized switch: %s"
|
||
|
||
CONFIG = {}
|
||
CONFIG[0] = $0
|
||
CONFIG[:USE_READLINE] = TRUE
|
||
CONFIG[:LOAD_MODULES] = []
|
||
CONFIG[:INSPECT] = nil
|
||
CONFIG[:TRACE_LOAD] = FALSE
|
||
CONFIG[:RC] = TRUE
|
||
|
||
CONFIG[:DEBUG] = FALSE
|
||
|
||
while opt = ARGV.shift
|
||
case opt
|
||
when "-d"
|
||
CONFIG[:DEBUG] = TRUE
|
||
when "-m"
|
||
CONFIG[:INSPECT] = FALSE if CONFIG[:INSPECT].nil?
|
||
require "mathn.rb"
|
||
include Math
|
||
when "-r"
|
||
opt = ARGV.shift
|
||
CONFIG[:LOAD_MODULES].push opt if opt
|
||
when "-f"
|
||
opt = ARGV.shift
|
||
CONFIG[:RC] = FALSE
|
||
when "--inspect"
|
||
CONFIG[:INSPECT] = TRUE
|
||
when "--noinspect"
|
||
CONFIG[:INSPECT] = FALSE
|
||
when "--noreadline"
|
||
CONFIG[:USE_READLINE] = FALSE
|
||
when /^-/
|
||
# print UnrecognizedSwitch.inspect, "\n"
|
||
BC_APPLICATION__.fail UnrecognizedSwitch, opt
|
||
else
|
||
CONFIG[:USE_READLINE] = FALSE
|
||
$0 = opt
|
||
break
|
||
end
|
||
end
|
||
CONFIG[:INSPECT] = TRUE if CONFIG[:INSPECT].nil?
|
||
|
||
PROMPTi = "rbc%d> "
|
||
PROMPTs = "rbc%d%s "
|
||
PROMPTe = "rbc%d* "
|
||
|
||
class BC
|
||
def initialize
|
||
lex_init
|
||
end
|
||
|
||
def eval_input(io, cont, bind)
|
||
line = ''
|
||
@io = io
|
||
@ltype = nil
|
||
@quoted = nil
|
||
@indent = 0
|
||
@lex_state = EXPR_BEG
|
||
|
||
@io.prompt = format(PROMPTi, @indent)
|
||
|
||
loop do
|
||
@continue = FALSE
|
||
l = @io.gets
|
||
|
||
unless l
|
||
break if line == ''
|
||
else
|
||
line = line + l
|
||
|
||
lex(l) if l != "\n"
|
||
print @quoted.inspect, "\n" if CONFIG[:DEBUG]
|
||
if @ltype
|
||
@io.prompt = format(PROMPTs, @indent, @ltype)
|
||
next
|
||
elsif @continue
|
||
@io.prompt = format(PROMPTe, @indent)
|
||
next
|
||
elsif @indent > 0
|
||
@io.prompt = format(PROMPTi, @indent)
|
||
next
|
||
end
|
||
end
|
||
|
||
if line != "\n"
|
||
begin
|
||
if CONFIG[:INSPECT]
|
||
print((cont._=eval(line, bind)).inspect, "\n")
|
||
else
|
||
print((cont._=eval(line, bind)), "\n")
|
||
end
|
||
rescue
|
||
# $! = 'exception raised' unless $!
|
||
# print "ERR: ", $!, "\n"
|
||
$! = RuntimeError.new("exception raised") unless $!
|
||
print $!.type, ": ", $!, "\n"
|
||
end
|
||
end
|
||
break if not l
|
||
line = ''
|
||
indent = 0
|
||
@io.prompt = format(PROMPTi, indent)
|
||
end
|
||
print "\n"
|
||
end
|
||
|
||
EXPR_BEG = :EXPR_BEG
|
||
EXPR_MID = :EXPR_MID
|
||
EXPR_END = :EXPR_END
|
||
EXPR_ARG = :EXPR_ARG
|
||
EXPR_FNAME = :EXPR_FNAME
|
||
|
||
CLAUSE_STATE_TRANS = {
|
||
"alias" => EXPR_FNAME,
|
||
"and" => EXPR_BEG,
|
||
"begin" => EXPR_BEG,
|
||
"case" => EXPR_BEG,
|
||
"class" => EXPR_BEG,
|
||
"def" => EXPR_FNAME,
|
||
"defined?" => EXPR_END,
|
||
"do" => EXPR_BEG,
|
||
"else" => EXPR_BEG,
|
||
"elsif" => EXPR_BEG,
|
||
"end" => EXPR_END,
|
||
"ensure" => EXPR_BEG,
|
||
"for" => EXPR_BEG,
|
||
"if" => EXPR_BEG,
|
||
"in" => EXPR_BEG,
|
||
"module" => EXPR_BEG,
|
||
"nil" => EXPR_END,
|
||
"not" => EXPR_BEG,
|
||
"or" => EXPR_BEG,
|
||
"rescue" => EXPR_MID,
|
||
"return" => EXPR_MID,
|
||
"self" => EXPR_END,
|
||
"super" => EXPR_END,
|
||
"then" => EXPR_BEG,
|
||
"undef" => EXPR_FNAME,
|
||
"unless" => EXPR_BEG,
|
||
"until" => EXPR_BEG,
|
||
"when" => EXPR_BEG,
|
||
"while" => EXPR_BEG,
|
||
"yield" => EXPR_END
|
||
}
|
||
|
||
ENINDENT_CLAUSE = [
|
||
"case", "class", "def", "do", "for", "if",
|
||
"module", "unless", "until", "while", "begin" #, "when"
|
||
]
|
||
DEINDENT_CLAUSE = ["end" #, "when"
|
||
]
|
||
|
||
PARCENT_LTYPE = {
|
||
"q" => "\'",
|
||
"Q" => "\"",
|
||
"x" => "\`",
|
||
"r" => "\/"
|
||
}
|
||
|
||
PARCENT_PAREN = {
|
||
"{" => "}",
|
||
"[" => "]",
|
||
"<" => ">",
|
||
"(" => ")"
|
||
}
|
||
|
||
def lex_init()
|
||
@OP = Trie.new
|
||
@OP.def_rules("\0", "\004", "\032"){}
|
||
@OP.def_rules(" ", "\t", "\f", "\r", "\13") do
|
||
@space_seen = TRUE
|
||
next
|
||
end
|
||
@OP.def_rule("#") do
|
||
|op, rests|
|
||
@ltype = "#"
|
||
identify_comment(rests)
|
||
end
|
||
@OP.def_rule("\n") do
|
||
print "\\n\n" if CONFIG[:DEBUG]
|
||
if @lex_state == EXPR_BEG || @lex_state == EXPR_FNAME
|
||
@continue = TRUE
|
||
else
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
end
|
||
@OP.def_rules("*", "*=", "**=", "**") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules("!", "!=", "!~") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules("=", "==", "===", "=~", "<=>") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules("<", "<=", "<<") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules(">", ">=", ">>") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules("'", '"') do
|
||
|op, rests|
|
||
@ltype = op
|
||
@quoted = op
|
||
identify_string(rests)
|
||
end
|
||
@OP.def_rules("`") do
|
||
|op, rests|
|
||
if @lex_state != EXPR_FNAME
|
||
@ltype = op
|
||
@quoted = op
|
||
identify_string(rests)
|
||
end
|
||
end
|
||
@OP.def_rules('?') do
|
||
|op, rests|
|
||
@lex_state = EXPR_END
|
||
identify_question(rests)
|
||
end
|
||
@OP.def_rules("&", "&&", "&=", "|", "||", "|=") do
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
@OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) {}
|
||
@OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) {}
|
||
@OP.def_rules("+=", "-=") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules("+", "-") do
|
||
|op, rests|
|
||
if @lex_state == EXPR_ARG
|
||
if @space_seen and rests[0] =~ /[0-9]/
|
||
identify_number(rests)
|
||
else
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
elsif @lex_state != EXPR_END and rests[0] =~ /[0-9]/
|
||
identify_number(rests)
|
||
else
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
end
|
||
@OP.def_rule(".") do
|
||
|op, rests|
|
||
@lex_state = EXPR_BEG
|
||
if rests[0] =~ /[0-9]/
|
||
rests.unshift op
|
||
identify_number(rests)
|
||
else
|
||
# obj.if <20>ʤɤ<CAA4><C9A4>б<EFBFBD>
|
||
identify_identifier(rests, TRUE)
|
||
@lex_state = EXPR_ARG
|
||
end
|
||
end
|
||
@OP.def_rules("..", "...") {@lex_state = EXPR_BEG}
|
||
|
||
lex_int2
|
||
end
|
||
|
||
def lex_int2
|
||
@OP.def_rules("]", "}", ")") do
|
||
@lex_state = EXPR_END
|
||
@indent -= 1
|
||
end
|
||
@OP.def_rule(":") {|op,rests|
|
||
identify_identifier(rests, TRUE)
|
||
}
|
||
@OP.def_rule("::") {|op,rests|
|
||
identify_identifier(rests, TRUE);
|
||
}
|
||
@OP.def_rule("/") do
|
||
|op, rests|
|
||
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
|
||
@ltype = op
|
||
@quoted = op
|
||
identify_string(rests)
|
||
elsif rests[0] == '='
|
||
rests.shift
|
||
@lex_state = EXPR_BEG
|
||
elsif @lex_state == EXPR_ARG and @space_seen and rests[0] =~ /\s/
|
||
@ltype = op
|
||
@quoted = op
|
||
identify_string(rests)
|
||
else
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
end
|
||
@OP.def_rules("^", "^=") {@lex_state = EXPR_BEG}
|
||
@OP.def_rules(",", ";") {@lex_state = EXPR_BEG}
|
||
@OP.def_rule("~") {@lex_state = EXPR_BEG}
|
||
@OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) {}
|
||
@OP.def_rule("(") do
|
||
@lex_state = EXPR_BEG
|
||
@indent += 1
|
||
end
|
||
@OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) {}
|
||
@OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) {}
|
||
@OP.def_rule("[") do
|
||
@indent += 1
|
||
if @lex_state != EXPR_FNAME
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
end
|
||
@OP.def_rule("{") do
|
||
@lex_state = EXPR_BEG
|
||
@indent += 1
|
||
end
|
||
@OP.def_rule('\\') {|op, rests| identify_escape(rests)} #')
|
||
@OP.def_rule('%') do
|
||
|op, rests|
|
||
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
|
||
identify_quotation(rests)
|
||
elsif rests[0] == '='
|
||
rests.shift
|
||
elsif @lex_state == EXPR_ARG and @space_seen and rests[0] =~ /\s/
|
||
identify_quotation(rests)
|
||
else
|
||
@lex_state = EXPR_BEG
|
||
end
|
||
end
|
||
@OP.def_rule('$') do
|
||
|op, rests|
|
||
identify_gvar(rests)
|
||
end
|
||
@OP.def_rule('@') do
|
||
|op, rests|
|
||
if rests[0] =~ /[\w_]/
|
||
rests.unshift op
|
||
identify_identifier(rests)
|
||
end
|
||
end
|
||
@OP.def_rule("def", proc{|op, chrs| /\s/ =~ chrs[0]}) do
|
||
|op, rests|
|
||
@indent += 1
|
||
@lex_state = EXPR_END
|
||
until rests[0] == "\n" or rests[0] == ";"
|
||
rests.shift
|
||
end
|
||
end
|
||
@OP.def_rule("") do
|
||
|op, rests|
|
||
printf "MATCH: start %s: %s\n", op, rests.inspect if CONFIG[:DEBUG]
|
||
if rests[0] =~ /[0-9]/
|
||
identify_number(rests)
|
||
elsif rests[0] =~ /[\w_]/
|
||
identify_identifier(rests)
|
||
end
|
||
printf "MATCH: end %s: %s\n", op, rests.inspect if CONFIG[:DEBUG]
|
||
end
|
||
|
||
p @OP if CONFIG[:DEBUG]
|
||
end
|
||
|
||
def lex(l)
|
||
chrs = l.split(//)
|
||
tokens = []
|
||
|
||
case @ltype
|
||
when "'", '"', '`', '/'
|
||
identify_string(chrs)
|
||
return if chrs.empty?
|
||
when "#"
|
||
identify_comment(chrs)
|
||
return
|
||
when "="
|
||
if l =~ /^=end/
|
||
$ltype = nil
|
||
return
|
||
end
|
||
else
|
||
if l =~ /^=begin/
|
||
$ltype = "="
|
||
return
|
||
end
|
||
end
|
||
|
||
until chrs.empty?
|
||
@space_seen = FALSE
|
||
printf "perse: %s\n", chrs.join("") if CONFIG[:DEBUG]
|
||
@OP.match(chrs)
|
||
printf "lex_state: %s continue: %s\n", @lex_state.id2name, @continue if CONFIG[:DEBUG]
|
||
end
|
||
end
|
||
|
||
def identify_gvar(chrs)
|
||
@lex_state = EXPR_END
|
||
|
||
ch = chrs.shift
|
||
case ch
|
||
when /[_~*$?!@/\\;,.=:<>"]/ #"
|
||
return
|
||
|
||
when "-"
|
||
ch = chrs.shift
|
||
return
|
||
|
||
when "&", "`", "'", "+"
|
||
return
|
||
|
||
when /[1-9]/
|
||
chrs.unshift ch
|
||
v = "$"
|
||
while (ch = chrs.shift) =~ /[0-9]/
|
||
end
|
||
chrs.unshift ch
|
||
return
|
||
|
||
when /\w/
|
||
chrs.unshift ch
|
||
chrs.unshift "$"
|
||
identify_identifier(chrs)
|
||
return
|
||
|
||
else
|
||
chrs.unshift ch
|
||
return
|
||
end
|
||
end
|
||
|
||
def identify_identifier(chrs, escaped = FALSE)
|
||
token = ""
|
||
token.concat chrs.shift if chrs[0] =~ /[$@]/ or escaped
|
||
while (ch = chrs.shift) =~ /\w|_/
|
||
print ":", ch, ":" if CONFIG[:DEBUG]
|
||
token.concat ch
|
||
end
|
||
chrs.unshift ch
|
||
|
||
if ch == "!" or ch == "?"
|
||
chrs.shift
|
||
token.concat ch
|
||
end
|
||
# fix token
|
||
|
||
if token =~ /^[$@]/ or escaped
|
||
@lex_state = EXPR_END
|
||
return
|
||
end
|
||
|
||
print token, "\n" if CONFIG[:DEBUG]
|
||
if state = CLAUSE_STATE_TRANS[token]
|
||
if @lex_state != EXPR_BEG and token =~ /^(if|unless|while|until)/
|
||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
else
|
||
if ENINDENT_CLAUSE.include?(token)
|
||
@indent += 1
|
||
elsif DEINDENT_CLAUSE.include?(token)
|
||
@indent -= 1
|
||
end
|
||
end
|
||
@lex_state = state
|
||
return
|
||
end
|
||
if @lex_state == EXPR_FNAME
|
||
@lex_state = EXPR_END
|
||
if chrs[0] == '='
|
||
chrs.shift
|
||
end
|
||
elsif @lex_state == EXPR_BEG
|
||
@lex_state = EXPR_ARG
|
||
else
|
||
@lex_state = EXPR_END
|
||
end
|
||
end
|
||
|
||
def identify_quotation(chrs)
|
||
ch = chrs.shift
|
||
if lt = PARCENT_LTYPE[ch]
|
||
ch = chrs.shift
|
||
else
|
||
lt = "\""
|
||
end
|
||
if ch !~ /\W/
|
||
chrs.unshift ch
|
||
next
|
||
end
|
||
@ltype = lt
|
||
unless @quoted = PARCENT_PAREN[ch]
|
||
@quoted = ch
|
||
end
|
||
identify_string(chrs)
|
||
end
|
||
|
||
def identify_number(chrs)
|
||
@lex_state = EXPR_END
|
||
|
||
ch = chrs.shift
|
||
case ch
|
||
when /0/
|
||
if (ch = chrs[0]) == "x"
|
||
chrs.shift
|
||
match = /[0-9a-f_]/
|
||
else
|
||
match = /[0-7_]/
|
||
end
|
||
while ch = chrs.shift
|
||
if ch !~ match
|
||
chrs.unshift ch
|
||
break
|
||
end
|
||
end
|
||
return
|
||
end
|
||
|
||
while ch = chrs.shift
|
||
case ch
|
||
when /[0-9]/
|
||
when "e", "E"
|
||
# type = FLOAT
|
||
unless (ch = chrs.shift) == "+" or ch == "-"
|
||
chrs.unshift ch
|
||
end
|
||
when "."
|
||
# type = FLOAT
|
||
when "_"
|
||
else
|
||
chrs.unshift ch
|
||
return
|
||
end
|
||
end
|
||
end
|
||
|
||
def identify_question(chrs)
|
||
@lex_state = EXPR_END
|
||
|
||
if chrs.shift == "\\" #"
|
||
identify_escape(chrs)
|
||
end
|
||
end
|
||
|
||
def identify_string(chrs)
|
||
while ch = chrs.shift
|
||
if @quoted == ch
|
||
if @ltype == "/"
|
||
if chrs[0] =~ /i|o|n|e|s/
|
||
chrs.shift
|
||
end
|
||
end
|
||
@ltype = nil
|
||
@quoted = nil
|
||
@lex_state = EXPR_END
|
||
break
|
||
elsif ch == '\\' #'
|
||
identify_escape(chrs)
|
||
end
|
||
end
|
||
end
|
||
|
||
def identify_comment(chrs)
|
||
while ch = chrs.shift
|
||
if ch == "\\" #"
|
||
identify_escape(chrs)
|
||
end
|
||
if ch == "\n"
|
||
@ltype = nil
|
||
chrs.unshift ch
|
||
break
|
||
end
|
||
end
|
||
end
|
||
|
||
def identify_escape(chrs)
|
||
ch = chrs.shift
|
||
case ch
|
||
when "\n", "\r", "\f"
|
||
@continue = TRUE
|
||
when "\\", "n", "t", "r", "f", "v", "a", "e", "b" #"
|
||
when /[0-7]/
|
||
chrs.unshift ch
|
||
3.times do
|
||
ch = chrs.shift
|
||
case ch
|
||
when /[0-7]/
|
||
when nil
|
||
break
|
||
else
|
||
chrs.unshift ch
|
||
break
|
||
end
|
||
end
|
||
when "x"
|
||
2.times do
|
||
ch = chrs.shift
|
||
case ch
|
||
when /[0-9a-fA-F]/
|
||
when nil
|
||
break
|
||
else
|
||
chrs.unshift ch
|
||
break
|
||
end
|
||
end
|
||
when "M"
|
||
if (ch = chrs.shift) != '-'
|
||
chrs.unshift ch
|
||
elsif (ch = chrs.shift) == "\\" #"
|
||
identify_escape(chrs)
|
||
end
|
||
return
|
||
when "C", "c", "^"
|
||
if ch == "C" and (ch = chrs.shift) != "-"
|
||
chrs.unshift ch
|
||
elsif (ch = chrs.shift) == "\\" #"
|
||
identify_escape(chrs)
|
||
end
|
||
return
|
||
end
|
||
end
|
||
end
|
||
|
||
class Trie
|
||
extend Exception2MessageMapper
|
||
def_exception :ErrNodeNothing, "node nothing"
|
||
def_exception :ErrNodeAlreadyExists, "node already exists"
|
||
|
||
class Node
|
||
# postproc<6F><63><EFBFBD>ʤ<EFBFBD><CAA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݥΡ<DDA5><CEA1><EFBFBD>, nil<69><6C><EFBFBD><EFBFBD><EFBFBD>ʤ<EFBFBD><CAA4><EFBFBD><EFBFBD>ж<EFBFBD><D0B6>ݥΡ<DDA5><CEA1><EFBFBD>
|
||
def initialize(preproc = nil, postproc = nil)
|
||
@Tree = {}
|
||
@preproc = preproc
|
||
@postproc = postproc
|
||
end
|
||
|
||
attr :preproc, TRUE
|
||
attr :postproc, TRUE
|
||
|
||
def search(chrs, opt = nil)
|
||
return self if chrs.empty?
|
||
ch = chrs.shift
|
||
if node = @Tree[ch]
|
||
node.search(chrs, opt)
|
||
else
|
||
if opt
|
||
chrs.unshift ch
|
||
self.create_subnode(chrs)
|
||
else
|
||
Trie.fail ErrNodeNothing
|
||
end
|
||
end
|
||
end
|
||
|
||
def create_subnode(chrs, preproc = nil, postproc = nil)
|
||
if chrs.empty?
|
||
if @postproc
|
||
p node
|
||
Trie.fail ErrNodeAlreadyExists
|
||
else
|
||
print "Warn: change abstruct node to real node\n" if CONFIG[:DEBUG]
|
||
@preproc = preproc
|
||
@postproc = postproc
|
||
end
|
||
return self
|
||
end
|
||
|
||
ch = chrs.shift
|
||
if node = @Tree[ch]
|
||
if chrs.empty?
|
||
if node.postproc
|
||
p node
|
||
Trie.fail ErrNodeAlreadyExists
|
||
else
|
||
print "Warn: change abstruct node to real node\n" if CONFIG[:DEBUG]
|
||
node.preproc = preproc
|
||
node.postproc = postproc
|
||
end
|
||
else
|
||
node.create_subnode(chrs, preproc, postproc)
|
||
end
|
||
else
|
||
if chrs.empty?
|
||
node = Node.new(preproc, postproc)
|
||
else
|
||
node = Node.new
|
||
node.create_subnode(chrs, preproc, postproc)
|
||
end
|
||
@Tree[ch] = node
|
||
end
|
||
node
|
||
end
|
||
|
||
def match(chrs, op = "")
|
||
print "match>: ", chrs, "op:", op, "\n" if CONFIG[:DEBUG]
|
||
if chrs.empty?
|
||
if @preproc.nil? || @preproc.call(op, chrs)
|
||
printf "op1: %s\n", op if CONFIG[:DEBUG]
|
||
@postproc.call(op, chrs)
|
||
""
|
||
else
|
||
nil
|
||
end
|
||
else
|
||
ch = chrs.shift
|
||
if node = @Tree[ch]
|
||
if ret = node.match(chrs, op+ch)
|
||
return ch+ret
|
||
else
|
||
chrs.unshift ch
|
||
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
|
||
printf "op2: %s\n", op.inspect if CONFIG[:DEBUG]
|
||
@postproc.call(op, chrs)
|
||
return ""
|
||
else
|
||
return nil
|
||
end
|
||
end
|
||
else
|
||
chrs.unshift ch
|
||
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
|
||
printf "op3: %s\n", op if CONFIG[:DEBUG]
|
||
@postproc.call(op, chrs)
|
||
return ""
|
||
else
|
||
return nil
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
def initialize
|
||
@head = Node.new("")
|
||
end
|
||
|
||
def def_rule(token, preproc = nil, postproc = nil)
|
||
# print node.inspect, "\n" if CONFIG[:DEBUG]
|
||
postproc = proc if iterator?
|
||
node = create(token, preproc, postproc)
|
||
end
|
||
|
||
def def_rules(*tokens)
|
||
if iterator?
|
||
p = proc
|
||
end
|
||
for token in tokens
|
||
def_rule(token, nil, p)
|
||
end
|
||
end
|
||
|
||
def preporc(token, proc)
|
||
node = search(token)
|
||
node.preproc=proc
|
||
end
|
||
|
||
def postproc(token)
|
||
node = search(token, proc)
|
||
node.postproc=proc
|
||
end
|
||
|
||
def search(token)
|
||
@head.search(token.split(//))
|
||
end
|
||
|
||
def create(token, preproc = nil, postproc = nil)
|
||
@head.create_subnode(token.split(//), preproc, postproc)
|
||
end
|
||
|
||
def match(token)
|
||
token = token.split(//) if token.kind_of?(String)
|
||
ret = @head.match(token)
|
||
printf "match end: %s:%s", ret, token.inspect if CONFIG[:DEBUG]
|
||
ret
|
||
end
|
||
|
||
def inspect
|
||
format("<Trie: @head = %s>", @head.inspect)
|
||
end
|
||
end
|
||
|
||
if /^-tt(.*)$/ =~ ARGV[0]
|
||
# Tracer.on
|
||
case $1
|
||
when "1"
|
||
tr = Trie.new
|
||
print "0: ", tr.inspect, "\n"
|
||
tr.def_rule("=") {print "=\n"}
|
||
print "1: ", tr.inspect, "\n"
|
||
tr.def_rule("==") {print "==\n"}
|
||
print "2: ", tr.inspect, "\n"
|
||
|
||
print "case 1:\n"
|
||
print tr.match("="), "\n"
|
||
print "case 2:\n"
|
||
print tr.match("=="), "\n"
|
||
print "case 3:\n"
|
||
print tr.match("=>"), "\n"
|
||
|
||
when "2"
|
||
tr = Trie.new
|
||
print "0: ", tr.inspect, "\n"
|
||
tr.def_rule("=") {print "=\n"}
|
||
print "1: ", tr.inspect, "\n"
|
||
tr.def_rule("==", proc{FALSE}) {print "==\n"}
|
||
print "2: ", tr.inspect, "\n"
|
||
|
||
print "case 1:\n"
|
||
print tr.match("="), "\n"
|
||
print "case 2:\n"
|
||
print tr.match("=="), "\n"
|
||
print "case 3:\n"
|
||
print tr.match("=>"), "\n"
|
||
end
|
||
exit
|
||
end
|
||
|
||
module CONTEXT
|
||
def _=(value)
|
||
CONFIG[:_] = value
|
||
eval "_=BC_APPLICATION__::CONFIG[:_]", CONFIG[:BIND]
|
||
end
|
||
|
||
# def _
|
||
# eval "_", CONFIG[:BIND]
|
||
# end
|
||
|
||
def quit
|
||
exit
|
||
end
|
||
|
||
def trace_load(opt = nil)
|
||
if !opt.nil?
|
||
CONFIG[:TRACE_LOAD] = opt
|
||
else
|
||
CONFIG[:TRACE_LOAD] = !CONFIG[:TRACE_LOAD]
|
||
end
|
||
print "Switch to load/require #{unless CONFIG[:TRACE_LOAD]; ' non';end} trace mode.\n"
|
||
if CONFIG[:TRACE_LOAD]
|
||
eval %{
|
||
class << self
|
||
alias load rbc_load
|
||
alias require rbc_require
|
||
end
|
||
}
|
||
else
|
||
eval %{
|
||
class << self
|
||
alias load rbc_load_org
|
||
alias require rbc_require_org
|
||
end
|
||
}
|
||
end
|
||
CONFIG[:TRACE_LOAD]
|
||
end
|
||
|
||
alias rbc_load_org load
|
||
def rbc_load(file_name)
|
||
return true if load_sub(file_name)
|
||
raise LoadError, "No such file to load -- #{file_name}"
|
||
end
|
||
|
||
alias rbc_require_org require
|
||
def rbc_require(file_name)
|
||
rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
|
||
return false if $".find{|f| f =~ rex}
|
||
|
||
case file_name
|
||
when /\.rb$/
|
||
if load_sub(file_name)
|
||
$".push file_name
|
||
return true
|
||
end
|
||
when /\.(so|o|sl)$/
|
||
rbc_require_org(file_name)
|
||
end
|
||
|
||
if load_sub(f = file_name + ".rb")
|
||
$".push f
|
||
return true
|
||
end
|
||
rbc_require_org(file_name)
|
||
end
|
||
|
||
def load_sub(fn)
|
||
if fn =~ /^#{Regexp.quote(File::Separator)}/
|
||
return false unless File.exist?(fn)
|
||
BC.new.eval_input FileInputMethod.new(fn), self, CONFIG[:BIND]
|
||
return true
|
||
end
|
||
|
||
for path in $:
|
||
if File.exist?(f = File.join(path, fn))
|
||
BC.new.eval_input FileInputMethod.new(f), self, CONFIG[:BIND]
|
||
return true
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
def inspect_mode(opt = nil)
|
||
if opt
|
||
CONFIG[:INSPECT] = opt
|
||
else
|
||
CONFIG[:INSPECT] = !CONFIG[:INSPECT]
|
||
end
|
||
print "Switch to#{unless CONFIG[:INSPECT]; ' non';end} inspect mode.\n"
|
||
CONFIG[:INSPECT]
|
||
end
|
||
|
||
def run(bind)
|
||
CONFIG[:BIND] = bind
|
||
|
||
if CONFIG[:RC]
|
||
rc = File.expand_path("~/.irbrc")
|
||
if File.exists?(rc)
|
||
begin
|
||
load rc
|
||
rescue
|
||
print "load error: #{rc}\n"
|
||
print $!.type, ": ", $!, "\n"
|
||
for err in $@[0, $@.size - 2]
|
||
print "\t", err, "\n"
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if CONFIG[:TRACE_LOAD]
|
||
trace_load true
|
||
end
|
||
|
||
for m in CONFIG[:LOAD_MODULES]
|
||
begin
|
||
require m
|
||
rescue
|
||
print $@[0], ":", $!.type, ": ", $!, "\n"
|
||
end
|
||
end
|
||
|
||
if !$0.equal?(CONFIG[0])
|
||
io = FileInputMethod.new($0)
|
||
elsif defined? Readline
|
||
io = ReadlineInputMethod.new
|
||
else
|
||
io = StdioInputMethod.new
|
||
end
|
||
|
||
BC.new.eval_input io, self, CONFIG[:BIND]
|
||
end
|
||
end
|
||
|
||
class InputMethod
|
||
attr :prompt, TRUE
|
||
|
||
def gets
|
||
end
|
||
public :gets
|
||
end
|
||
|
||
class StdioInputMethod < InputMethod
|
||
def gets
|
||
print @prompt
|
||
$stdin.gets
|
||
end
|
||
end
|
||
|
||
class FileInputMethod < InputMethod
|
||
def initialize(file)
|
||
@io = open(file)
|
||
end
|
||
|
||
def gets
|
||
l = @io.gets
|
||
print @prompt, l
|
||
l
|
||
end
|
||
end
|
||
|
||
if CONFIG[:USE_READLINE]
|
||
begin
|
||
require "readline"
|
||
print "use readline module\n"
|
||
class ReadlineInputMethod < InputMethod
|
||
include Readline
|
||
def gets
|
||
if l = readline(@prompt, TRUE)
|
||
l + "\n"
|
||
else
|
||
l
|
||
end
|
||
end
|
||
end
|
||
rescue
|
||
CONFIG[:USE_READLINE] = FALSE
|
||
end
|
||
end
|
||
end
|
||
|
||
extend BC_APPLICATION__::CONTEXT
|
||
run(binding)
|
||
|