1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/sample/rbc.rb

963 lines
19 KiB
Ruby
Raw Normal View History

#!/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{}