`
roki
  • 浏览: 60377 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

《搜索引擎零距离》第三章 IRS虚拟机及编译器实现原理(1)

阅读更多
    IRS语言运行于Java编写的虚拟机上,本书把运行IRS语言的虚拟机称为IRVM(Information Retrieval Virtual Machine),而这个虚拟机上最为重要的一个模块就是内嵌的Ruby解析引擎,IRS语言中的Ruby脚本可以调用IRVM内部的多种功能模块,并能灵活地处理各种循环、条件判断语句,以及Ruby语言的系统函数。下面对Ruby,Java,JRuby作一简单介绍。Ruby是现在编程界讨论得正热火朝天的一种语言。这种语言功能强大而且易于使用;同时Ruby还紧密绑定到例如Ruby on Rails等web应用程序开发框架中。另一方面,在过去的十年间,Java正迅速成长为业界领先的面向对象的软件开发语言并且运行于诸多平台之上。而 JRuby则是一个100%的Ruby编程语言的纯Java实现。
Ruby已经成为席卷计算世界的脚本化语言。近几个月来,在编程领域的几乎每一个人可能都会耳濡目染Ruby。日益盛行的Ruby on Rails web开发框架正在帮助使Ruby成为快速开发和测试应用程序的一门语言。作为一种解释性的脚本化语言,Ruby提供了快速而容易的面向对象编程技术,同时还提供了许多非常干净利索的特征,例如closure,块和mixins。另外,Ruby还是高度可移植的,可以广泛运行于Unix/Linux, Windows以及MacOS平台之上。
  Java已经走过了辉煌的面向对象语言的十年。Java最早由Sun Microsystems的James Gosling在上一世纪九十年代创建。当时,Gosling开发这一语言的主要目的是想提供一种虚拟机和一种C风格的标志语言,同时使之具有比C/C++更为一致和简单的特征。Java的另一个主要的目标是提供一种“编写一次处处都能运行”(WORA)的理想语言,允许一个程序在一种平台上开发而能够不经任何重编译即可运行于另一种平台。这个Java平台由一个Java运行时刻环境和Java软件开发包(SDK)组成。现在,Java能够为从移动设备到企业系统的诸多平台提供SDK,这分别对应于它的JavaSE、EE和ME技术。在过去的十年间,Java已经被广泛应用于移动设备、无人值守系统、 Web应用程序、金融系统以及实时系统等众多开发领域。
  JRuby则是一个100%的Ruby编程语言的纯Java实现,这种语言在CPL、GPL和LGPL三种开源许可下发行。它是一个1.8.4 Ruby解释器,其中提供了大多数Ruby的内置类。JRuby支持从一个Ruby程序中定义Java类并实现与之交互,另外还对Bean脚本化框架实现支持。 在本文成文之时,JRuby的当前版本是1.0.1。JRuby使Ruby程序能够存取Java类,允许它们作为程序内使用的一级对象。如今, JRuby的创始人,Thomas Enebo和Charles Nutter,已经受雇于Sun专门研究并开发JRuby。
3.1 Ruby基本语法
首先介绍一下Ruby的基本语法.
3.1.1 字句构造和表达式
在 Ruby 中是区分大写字母和小写字母的,注意不要弄错了。除标识符和一部分字面值中间外,空字符和注释的位置是没有限制的。空字符包括 space、tab、垂直 tab、backspace、回车和换页。换行比较特殊,如果是一行的内容转到下一行继续就作为空字符,除此之外解释为语句的切分。

4. 标识符
例子:
foobar
ruby_is_simple

Ruby 的标识符,以字母或_开始,后面是字母、_或数字。没有长度的限制。

5. 注释
例:
# this is a comment line

除在字符串中间以外,其他 # 符号后面的一整行文字都会被认定为注释。

6. 保留字
Ruby中保留字如下:

BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined for      or       then     yield
and      do       if       redo     true
begin    else     in       rescue   undef
break    elsif    module   retry    unless
case     end      next     return   until

保留字不能作为类名称、变量名称等使用。但是如果以接头符 $、@ 等开头,就不再是保留字。
7. 表达式
例:
true
(1+2)*3
foo()
if test then ok else ng end
变量、常量、字面值、运算式和控制结构等统称为表达式。将表达式排列起来就成为 Ruby 的程序。表达式和表达式之间以分号(;)或换行符分开。但是,紧跟反斜线符号(\)的换行并非分隔符,而是表示到下一行继续。还可以使用括号将表达式括起来进行群组化。
3.1.2 字面值
像数字1和字符串hello world这样在Ruby 程序中直接描述的内容就是字面值。
1. 数字字面值
(1) 整数:如123,0d123。
(2) 带符号整数:如-123。
(3) 浮点数:浮点数不能写成像 .1 这样直接以.开头的样式,必须要写成 0.1。如123.45,1.2e-3
(4) 十六进制整数:如0xffff
(5) 二进制整数:如0b1011
(6) 八进制整数:如0o377
在数字字面值中可以插入“_”。Ruby 编译器会忽略“_”,不会对其作特别的处理。这样在那些数值很大的数字中加入“_”,会很方便地快速看清楚其位数而了解其值的大小。但应特别注意的是, “_”加在字面值的开头(若在字面值开头则包括“+、-”号与字面值间的位置)和结尾,或连续写入多个“_”都是不充许的(会误认成局部变量或方法调用)。
1_000_000_000   # => 1000000000
0xffff_ffff     # => 0xffffffff

2. 字符串字面值
例子:
"this is a string expression\n"
'this is a string expression'
以双引号或单引号包围的字符串是 String 类的实例。以双引号包围的字符串控制码和内嵌表达式都是有效的。而以单引号包围的字符串,除了 \\(反斜线符号本身)、\’(单引号)和行尾的 \(忽略换行)外,其它的在字符串中将不作处理。
中间夹有空字符的多个字符串字面值会被当作一个字符串字面值来处理。
例子:
p "foo" "bar"   # => "foobar"
控制码:反斜线符号 \ 是字符串中的特殊符号,当作控制码使用。
\t Tab(0x09)
\n 换行(0x0a)
\r 回车(0x0d)
\f 换页(0x0c)
\s 空格(0x20)
\nnn 八进制代码(n 是 0-7)
\xnn 十六进制代码(n 是 0-9,a-f)
3. 内嵌表达式
在双引号(")包围的字符串和正则表达式中,可以使用“#{表达式}”的形式把表达式的内容(以字符串的形式)嵌入其中。表达式为以变量符号($、 @)开头的变量时能够省略{},以“#变量名”的形式就可以了。如果# 后不是跟着 {、$、@,就会被仅当作字符“#”解释。如果确定不使用内嵌表达式的话在 # 前放置一个反斜线符号就可以了。
$ruby = "RUBY"
p "my name is #{$ruby}"     # => "my name is RUBY"
p ’my name is #{$ruby}’     # => "my name is #{$ruby}"

4. 正则表达式字面值
例子:
/^Ruby the OOPL/
/Ruby/i
/my name is #{myname}/
/包围的部分就是正则表达式。正则表达式是 Regexp 类的实例。最后的 / 之后的字符是正则表达式的选项。选项的功能如下:
 i:正则表达式匹配时不区分大小写字母。
 m:多行模式。正则表达式.也能匹配换行。
 o:开始计算正则表达式时只处理一次内嵌表达式。
 x: 正则表达式中的空字符(包括换行)将被忽视。同时,从“#”到行尾的部分将被当作注释处理(请注意,若注释中包含/则会引起语法解析错误)。
    /foo        # 注释
     bar/x

    等同于“/foobar/”。
Ruby 正则表达式能正确使用多字节字符(汉字等)。正则表达式和字符串一样,其中的控制码和内嵌表达式也是有效的。如果正则表达式字面值中不含内嵌表达式的话,则对其进行计算时始终返回同一个正则表达式对象;如果含有内嵌表达式的话,每计算一次(根据内嵌表达式的结果)就编译正则表达式并生成一个正则表达式对象。
5. 数组表达式
例子:
[1, 2, 3]

语法:
' [' 表达式 ', ' ... '] '
分别计算每个表达式的值,然后返回由这些值构成的数组。数组是 Array 类的实例。每次对数组表达式进行计算时都会生成新的数组对象。
6. 哈希表表达式
例子:
{1=>2, 2=>4, 3=>6}
语法:
'{'表达式'=>'表达式', ' ... '}'
'{'表达式', '表达式', ' ... '}'
分别计算每个表达式的值,返回由主键和数值组成的哈希表对象。哈希表是 Hash 类的实例。哈希表(也叫作关联数组)就是把任意种类的对象和另一任意种类的对象进行关联。每次对哈希表表达式进行计算时都会生成新的哈希表对象。
7. 范围表达式
例子:
1 .. 20
语法:
式1 '.. '式'
式1 '... '式2
在条件式以外的地方返回从式 1 到式 2 的范围对象。范围对象是 Range 类的实例。
.. 运算符生成的范围对象包含后面的数值,...运算符生成的范围对象不包含后面数值。如果范围式两端是数值字面值的话,每次计算都会返回同一个对象,否则每次计算都会生成一个新的范围对象。
8. 符号
例子:
:class
:lvar
:method
:$gvar
:@ivar
:+
语法:
': ' 标识符
': ' 变量名
': ' 运算符
返回任意字符串和相对应的符号。符号是 Symbol 类的实例。通常符号总是只有单个对象,无论被计算多少次也只会返回同一个对象。
3.1.3 控制结构
与C语言等不同,Ruby 的控制结构是表达式,其中一部分还会返回值。也有不返回值的。若把这些不返回值的表达式放在赋值表达式右边的话,就会发生解析错误(parse error)。
Ruby 中包括从 C 和 Perl 那里继承来的控制结构,还包括一种可以将控制结构抽象化的功能,即迭代器。迭代器的调用使类的设计者可以自己定义一些包括循环在内的控制结构。

1. 条件分支 if
例子:
if age >= 12 then
  print "adult fee\n"
else
  print "child fee\n"
end
gender = if foo.gender == "male" then "male" else "female" end
语法:
if 条件表达式1 [then]
  表达式1 ...
[elsif 条件表达式2 [then]
  表达式2 ... ]
...
[else
  表达式n ... ]
end
若条件表达式1的结果为真,则执行 then 以下的表达式1。若条件表达式1为假时,计算 elsif 的条件表达式部分。可以存在若干个 elsif 部分。若所有的 if 以及 elsif 的条件表达式都为假的话,如果有 else 部分,则执行它的表达式n。if 表达式的结果取决于条件成立部分(或 else 部分)中最后被计算的表达式的结果。若没有 else 部分,且所有条件均不成立的话,就返回 nil。
Ruby 中只有 false 和 nil 表示假,其他的都是真,甚至 0 或空字符串也是如此。
请注意,在 Ruby 中,和if对应的是elsif,而并非 else if(此为C语言的语句)或者elif(此为sh的语句)。
2. if 修饰符
例子:
print "debug\n" if $DEBUG
语法:
表达式 if 表达式
当if右边的条件成立时,执行if左边的表达式,并返回其结果。若条件表达式不成立,则返回 nil。
3. 条件分支unless
例子:
unless baby?
  feed_meat
else
  feed_milk
end
语法:
unless 表达式 [then]
  表达式 ...
[else
  表达式 ... ]
end
unless 与 if 相反,当条件表达式结果为伪时,才执行then 后面的表达式。unless 表达式中不能插入 elsif 语句。
4. unless 修饰符
例子:
print "stop\n" unless valid(passwd)
语法:
表达式 unless 表达式
当右边的条件不成立时,计算左边的表达式,并返回其结果。否则返回 nil。
5. case选择
例子:
case $age
when 0 .. 2
  "baby"
when 3 .. 6
  "little child"
when 7 .. 12
  "child"
when 13 .. 18
  "youth"
else
  "adult"
end
语法:
case 表达式
[when 表达式 [, 表达式] ... [then]
  表达式 ..]..
[else
  表达式 ..]
end
case 先对一个表达式进行匹配判断,然后根据匹配结果进行分支选择。它使用 === 运算符比较 when 的指定值和最初那个表达式的计算值,若一致的话就计算 when 部分的内容。case 将返回条件成立的 when 部分(或 else 部分)中最后被执行的表达式的结果。若所有条件都不成立,则返回 nil。
6. 循环while
例子:
ary = [0,2,4,8,16,32,64,128,256,512,1024]
i = 0
while i < ary.length
  print ary[i]
  i += 1
end
语法:
while 表达式 [do]
   ...
end
只要表达式的结果为真,就循环执行 while 语句中的内容。while 返回 nil。另外,可以使用带参数的 break,将 while 表达式的返回值设为那个参数的值。
7. while 修饰符
例子:
sleep(60) while io_not_ready?
语法:
表达式 while 表达式
只要while右边表达式的计算值为真,就循环执行while的左边部分。while 修饰符的表达式返回 nil。另外,可以使用带参数的 break,将 while 修饰符的表达式返回值设为那个参数的值。
8. until
例子:
until f.eof?
  print f.gets
end
语法:
until 表达式 [do]
   ...
end
在表达式的结果变为真之前,一直循环执行 until 中的内容,until 返回 nil。另外,可以使用带参数的 break,将 until 表达式的返回值设定为那个参数的值。
9. until 修饰符
例子:
print(f.gets) until f.eof?
语法:
表达式 until 表达式
在until右边表达式的结果变为真之前,一直循环执行左边部分。until 修饰符的表达式返回 nil。另外,可以使用带参数的 break,将 until 修饰符的表达式返回值设为那个参数的值。
10. for循环
例子:
for i in [1, 2, 3]
  print i*2, "\n"
end
语法:
for lhs ...  in 表达式 [do]
  表达式 ..
end
先执行表达式得到一个对象,然后分别针对该对象中的每个单元,循环执行 for 的内容。
11. break跳转
例子:
i = 0
while i < 3
  print i, "\n"
  break
end
语法:
break [表达式]
break 将退出最内层的循环。循环是指下列情形之一。
 while
 until
 for
 迭代
与 C 语言不同,break 只能从循环中退出,而不能从 case 中退出。若使用 break 退出 for 或迭代循环后,该循环将返回 nil。但如果使用了参数的话,循环将返回那个参数的值。
12. next跳转
例子:
str.each_line do |line|
  next if line.empty?
  print line
end
语法:
next [表达式]
next 将跳转到最内侧循环的开始。在迭代器中,它将跳离 yield 调用。用 next 跳离 yield 后,yield 表达式将返回 nil。但如果使用了参数的话,yield 表达式的返回值就是该参数的值。
13. 异常处理 raise
例子:
raise
raise "you lose"
raise SyntaxError.new("invalid syntax")
raise SyntaxError, "invalid syntax"

语法:
raise
raise message
raise exception
raise error_type, message
运行上述例子中的代码,引发异常。第一句将再次引发上一个异常;第二句中(参数为字符串的情况),就把那个字符串信息当作错误信息引发 RuntimeError 异常;第三句(参数为异常对象的情况),则引发该类型的异常。第四句中,将引发第一个参数所指的异常,并以第二个参数的内容作为错误信息。可以使用 begin 表达式的 rescue 部分来捕捉异常。
注意,raise 并不是 Ruby 的保留字,而是内部函数。
14. begin
例子:
begin
  do_something
rescue
  recover
ensure
  must_to_do
end

语法:
  表达式 ..
[rescue [error_type,..] [then]
  表达式 ..]..
[ensure
  表达式 ..]
end
若给出了 rescue 部分(可以有若干个),就可以在发生异常时捕捉到它。若存在与异常类型一致的 rescue 部分,就执行 rescue 的内容。发生异常时,可以使用内部变量 $! 来查看异常的情况。若 error_type 被省略,则将捕捉 StandardError 的子类中的所有异常。Ruby 的大部分内部异常是 StandardError 的子类。具体请参考内部异常类。
在 rescue 部分中,error_type 与普通的参数一样计算,若符合就执行相应部分的内容。若 error_type 的结果既非类又非模块的话,则引发 TypeError 异常。若存在 ensure 部分的话,则在 begin 表达式结束之前一定会计算它。begin 表达式返回自身或 rescue 部分最后的计算结果。
15. rescue 修饰符
例子:
File.open("file") rescue print "can’t open\n"
语法:
表达式1 rescue 表达式2
若表达式 1 中发生异常时就计算表达式 2。不能指定想捕捉的异常类(也就是说,只能捕捉 StandardError 异常类的子类)。在包含 rescue 修饰符的表达式中,若没发生异常则返回表达式 1 的值,若发生异常则返回表达式 2 的值。
16. 方法结束 return
例子:
return
return 12
return 1,2,3
语法:
return [表达式[’,’ 表达式 ... ]]
结束方法的运行,且把表达式的值设定为方法的返回值。若给出了两个以上的表达式,则将这些表达式组成一个数组,然后把该数组设定为方法的返回值。若省略表达式,则返回值为 nil。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics