mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
963 lines
19 KiB
Ruby
963 lines
19 KiB
Ruby
|
#!/usr/local/bin/ruby
|
|||
|
#
|
|||
|
# rbc.rb -
|
|||
|
# $Release Version: 0.6 $
|
|||
|
# $Revision: 1.2 $
|
|||
|
# $Date: 1997/11/27 13:46:06 $
|
|||
|
# by Keiju ISHITSUKA(Nippon Rational Inc.)
|
|||
|
#
|
|||
|
# --
|
|||
|
# Usage:
|
|||
|
#
|
|||
|
# rbc.rb [options] file_name opts
|
|||
|
# options:
|
|||
|
# -d <20>ǥХå<D0A5><C3A5>⡼<EFBFBD><E2A1BC>(<28><><EFBFBD>Ѥ<EFBFBD><D1A4>ʤ<EFBFBD><CAA4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɤ<EFBFBD><C9A4>Ǥ<EFBFBD><C7A4>礦)
|
|||
|
# -m bc<62>⡼<EFBFBD><E2A1BC>(ʬ<><CAAC>, <20><><EFBFBD><EFBFBD><EFBFBD>η<CEB7><D7BB><EFBFBD><EFBFBD>Ǥ<EFBFBD><C7A4>ޤ<EFBFBD>)
|
|||
|
# -r load-module ruby -r <20><>Ʊ<EFBFBD><C6B1>
|
|||
|
# --inspect <20><><EFBFBD>̽<EFBFBD><CCBD>Ϥ<EFBFBD>inspect<63><74><EFBFBD>Ѥ<EFBFBD><D1A4><EFBFBD>(bc<62>⡼<EFBFBD>ɰʳ<C9B0><CAB3>ϥ<EFBFBD>
|
|||
|
# <20>ե<EFBFBD><D5A5><EFBFBD><EFBFBD><EFBFBD>).
|
|||
|
# --noinspect <20><><EFBFBD>̽<EFBFBD><CCBD>Ϥ<EFBFBD>inspect<63><74><EFBFBD>Ѥ<EFBFBD><D1A4>ʤ<EFBFBD>.
|
|||
|
# --noreadline readline<6E>饤<EFBFBD>֥<EFBFBD><D6A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4>ʤ<EFBFBD>(<28>ǥե<C7A5><D5A5><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
# <20>Ǥ<EFBFBD>readline<6E>饤<EFBFBD>֥<EFBFBD><D6A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4>褦<EFBFBD>Ȥ<EFBFBD><C8A4><EFBFBD>).
|
|||
|
#
|
|||
|
# <20>ɲ<EFBFBD> private method:
|
|||
|
# exit, quit <20><>λ<EFBFBD><CEBB><EFBFBD><EFBFBD>.
|
|||
|
# inspect(sw = nil) <20><><EFBFBD>ڥ<F3A5B9A5><DAA5>ȥ⡼<C8A5>ɤΥȥ<CEA5><C8A5><EFBFBD>
|
|||
|
# trace_load(sw = nil) load/require<72><65><EFBFBD><EFBFBD>rbc<62><63>file<6C>ɤ߹<C9A4><DFB9>ߵ<EFBFBD>ǽ<EFBFBD><C7BD><EFBFBD><EFBFBD>
|
|||
|
# <20><><EFBFBD><EFBFBD><EFBFBD>⡼<EFBFBD>ɤΥ<C9A4><CEA5><EFBFBD><EFBFBD>å<EFBFBD>(<28>ǥե<C7A5><D5A5><EFBFBD><EFBFBD>Ȥϥȥ졼<C8A5><ECA1BC>
|
|||
|
# <20>⡼<EFBFBD><E2A1BC>)
|
|||
|
#
|
|||
|
require "e2mmap.rb"
|
|||
|
|
|||
|
$stdout.sync = TRUE
|
|||
|
|
|||
|
module BC_APPLICATION__
|
|||
|
RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/ruby/RCS/rbc.rb,v 1.2 1997/11/27 13:46:06 keiju Exp keiju $-'
|
|||
|
|
|||
|
extend Exception2MessageMapper
|
|||
|
def_exception :UnrecognizedSwitch, "Unrecognized switch: %s"
|
|||
|
|
|||
|
$DEBUG = FALSE
|
|||
|
$INSPECT = nil
|
|||
|
|
|||
|
CONFIG = {}
|
|||
|
CONFIG[0] = $0
|
|||
|
CONFIG[:USE_READLINE] = TRUE
|
|||
|
CONFIG[:LOAD_MODULES] = []
|
|||
|
CONFIG[:INSPECT] = nil
|
|||
|
CONFIG[:TRACE_LOAD] = TRUE
|
|||
|
|
|||
|
while opt = ARGV.shift
|
|||
|
case opt
|
|||
|
when "-d"
|
|||
|
$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 "--inspect"
|
|||
|
CONFIG[:INSPECT] = TRUE
|
|||
|
when "--noinspect"
|
|||
|
CONFIG[:INSPECT] = FALSE
|
|||
|
when "--noreadline"
|
|||
|
CONFIG[:USE_READLINE] = FALSE
|
|||
|
when /^-/
|
|||
|
# print UnrecognizedSwitch.inspect, "\n"
|
|||
|
BC.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 $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"]
|
|||
|
|
|||
|
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 $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)
|
|||
|
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.def_rule("::") {@lex_state = EXPR_BEG}
|
|||
|
@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("") do
|
|||
|
|op, rests|
|
|||
|
printf "match: start %s: %s", op, rests.inspect if $DEBUG
|
|||
|
if rests[0] =~ /[0-9]/
|
|||
|
identify_number(rests)
|
|||
|
elsif rests[0] =~ /[\w_]/
|
|||
|
identify_identifier(rests)
|
|||
|
end
|
|||
|
printf "match: end %s: %s", op, rests.inspect if $DEBUG
|
|||
|
end
|
|||
|
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 $DEBUG
|
|||
|
@OP.match(chrs)
|
|||
|
printf "lex_state: %s continue: %s\n", @lex_state.id2name, @continue if $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)
|
|||
|
token = ""
|
|||
|
token.concat chrs.shift if chrs[0] =~ /[$@]/
|
|||
|
while (ch = chrs.shift) =~ /\w|_/
|
|||
|
print ":", ch, ":" if $DEBUG
|
|||
|
token.concat ch
|
|||
|
end
|
|||
|
chrs.unshift ch
|
|||
|
|
|||
|
if ch == "!" or ch == "?"
|
|||
|
chrs.shift
|
|||
|
token.concat ch
|
|||
|
end
|
|||
|
# fix token
|
|||
|
|
|||
|
if token =~ /^[$@]/
|
|||
|
@lex_state = EXPR_END
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
print token, "\n" if $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
|
|||
|
|
|||
|
def preproc(p)
|
|||
|
@preproc = p
|
|||
|
end
|
|||
|
|
|||
|
def postproc(p)
|
|||
|
@postproc = p
|
|||
|
end
|
|||
|
|
|||
|
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)
|
|||
|
ch = chrs.shift
|
|||
|
if node = @Tree[ch]
|
|||
|
if chrs.empty?
|
|||
|
Trie.fail ErrNodeAlreadyExists
|
|||
|
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, "\n" if $DEBUG
|
|||
|
if chrs.empty?
|
|||
|
if @preproc.nil? || @preproc.call(op, chrs)
|
|||
|
printf "op1: %s\n", op if $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
|
|||
|
elsif @postproc and @preproc.nil? || @preproc.call(op, chrs)
|
|||
|
chrs.unshift ch
|
|||
|
printf "op2: %s\n", op if $DEBUG
|
|||
|
@postproc.call(op, chrs)
|
|||
|
return ""
|
|||
|
else
|
|||
|
chrs.unshift ch
|
|||
|
return nil
|
|||
|
end
|
|||
|
else
|
|||
|
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
|
|||
|
printf "op3: %s\n", op if $DEBUG
|
|||
|
chrs.unshift ch
|
|||
|
@postproc.call(op, chrs)
|
|||
|
return ""
|
|||
|
else
|
|||
|
chrs.unshift ch
|
|||
|
return nil
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
def initialize
|
|||
|
@head = Node.new("")
|
|||
|
end
|
|||
|
|
|||
|
def def_rule(token, preproc = nil, postproc = nil)
|
|||
|
node = search(token, :CREATE)
|
|||
|
# print node.inspect, "\n" if $DEBUG
|
|||
|
node.preproc(preproc)
|
|||
|
if iterator?
|
|||
|
node.postproc(proc)
|
|||
|
elsif postproc
|
|||
|
node.postproc(postproc)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
def def_rules(*tokens)
|
|||
|
if iterator?
|
|||
|
p = proc
|
|||
|
end
|
|||
|
for token in tokens
|
|||
|
def_rule(token, nil, p)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
def preporc(token)
|
|||
|
node = search(token)
|
|||
|
node.preproc proc
|
|||
|
end
|
|||
|
|
|||
|
def postproc(token)
|
|||
|
node = search(token)
|
|||
|
node.postproc proc
|
|||
|
end
|
|||
|
|
|||
|
def search(token, opt = nil)
|
|||
|
@head.search(token.split(//), opt)
|
|||
|
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 $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)
|
|||
|
@_ = value
|
|||
|
end
|
|||
|
|
|||
|
def _
|
|||
|
@_
|
|||
|
end
|
|||
|
|
|||
|
def quit
|
|||
|
exit
|
|||
|
end
|
|||
|
|
|||
|
def trace_load(opt = nil)
|
|||
|
if opt
|
|||
|
@Trace_require = opt
|
|||
|
else
|
|||
|
@Trace_require = !@Trace_require
|
|||
|
end
|
|||
|
print "Switch to load/require #{unless @Trace_require; ' non';end} trace mode.\n"
|
|||
|
if @Trace_require
|
|||
|
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
|
|||
|
@Trace_require
|
|||
|
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)$/
|
|||
|
require_org(file_name)
|
|||
|
end
|
|||
|
|
|||
|
if load_sub(f = file_name + ".rb")
|
|||
|
$:.push f
|
|||
|
end
|
|||
|
require(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(opt = nil)
|
|||
|
if opt
|
|||
|
CONFIG[:INSPECT] = opt
|
|||
|
else
|
|||
|
CONFIG[:INSPECT] = !$INSPECT
|
|||
|
end
|
|||
|
print "Switch to#{unless $INSPECT; ' non';end} inspect mode.\n"
|
|||
|
$INSPECT
|
|||
|
end
|
|||
|
|
|||
|
def run
|
|||
|
CONFIG[:BIND] = proc
|
|||
|
|
|||
|
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{}
|