mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
133ff3421a
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@695 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 StandardError, ScriptError
|
|
# $! = '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
|
|
# handle ``obj.if'' and such
|
|
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)/
|
|
# modifiers
|
|
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
|
|
# abstract node if postproc is nil.
|
|
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 LoadError
|
|
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 LoadError
|
|
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 LoadError
|
|
CONFIG[:USE_READLINE] = FALSE
|
|
end
|
|
end
|
|
end
|
|
|
|
extend BC_APPLICATION__::CONTEXT
|
|
run(binding)
|
|
|