【从菜鸟到高手】编程语言中的 eval 与 REPL

版权声明:欢迎转载 https://blog.csdn.net/antony1776/article/details/84201188

1 深入理解 Expression 与 Statement 的区别

在编程语言中,表达式(expression)与语句(statement)有着不同的内涵。只有理解了它们的不同,才能更加清楚的理解不同语言中 eval 的异同。

源代码在编译或解析执行时,首先会被输入到扫描器(Scanner,例如 lex)中,进行词法分析(lexical analysis),运用一种类似于有限状态机的算法将源代码中的字符序列分割为一系列的记号(Token)。这些 Token 一般可分为如下几类:关键字、标识符、字面量(如数字、字符串等)和特殊符号(+=-%&*$)。

接下来是语法分析(grammar analysis),产生语法树(syntax tree),这里的语法树就是以表达式(Expression)为节点的树。
在这里插入图片描述
那么什么是表达式呢?

表达式是编程语言中描述计算过程的基本工具!

表达式通常由常量(constants)、变量(variables)、操作符(operators)或函数(functions)组成,经过解析和计算,产生一个结果。在编程语言领域,表达式解析并产生结果的过程,称之为求值(Evaluation),也就是说表达式一定会对应一个结果值,这是表达式与语句最明显的不同。

语句,就是代码中的一句话,大多数语言都以“;”(分号)表示程序中的一句话,这就是最简单的程序语句,一个表达式也可以是一个语句,比如:

3+2; // 这就是一个简单的表达式语句

下面是自然语言中的语句:
在这里插入图片描述

语句是命令式编程语言(imperative programming language)最基本的语法单元,而赋值语句是命令式语言的核心概念。语句一般可分为:
1、 简单语句

  • assertion(断言)
  • assignment(赋值)
  • goto(跳转)
  • return(返回)
  • call(调用)

2、 复杂语句

  • 块语句:{…} 或 begin … end
  • 循环语句:while, for, …
  • 条件语句:if,else; switch
  • 异常捕获语句: try … catch

语句只是意味着完成一件事情,并不会产生一个结果,而表达式总会产生一个结果。

2 不同语言中的 eval 与 exec

正因为语句与表达式本质上是不同的,所以才会出现 eval 与 exec。

语句(statement)总是被执行(execute),表达式(expression)总是被计算(evaluation)。当然在实现过程中,不同语言对语句和表达式的区分程度不同。

2.1 JavaScript

JavaScript 中 eval 既能用于表达式求值,也能用于执行语句。

eval("foo += 2")    // Uncaught ReferenceError: foo is not defined(…)
eval("foo = 0")     // eval 执行赋值语句,声明 foo 变量,并赋值为 2
eval("foo + 2")     // eval 计算表达式结果,返回 2

eval 将字符串所表示的代码在程序中执行,可以实现动态编码的效果,例如,通过 eval 实现对 json 字符串的解析:

a = {
    name: "hello eval", 
    ids: [1,2,3,4], 
    attributes: { 
        color: "blue"
    }
}

s = JSON.stringify(a)   // "{"name":"hello eval","ids":[1,2,3,4],"attributes":{"color":"blue"}}"
eval("p = "+s)          // 等效于 p = JSON.parse(s)

2.2 Python

Python 中 eval 用于表达式求值,exec 用于执行语句。

eval("4+5")                 # 表达式求值
exec("y = {'a': 'hello'}")  # 执行语句

eval("a = 3")               # SyntaxError
eval("a + 3", {"a": 4})		# 7
x = 5
eval("x+1")					# 6
eval("print('OK')")         # OK

2.3 Ruby

Ruby 语言中的 eval 除了可以对表达式求值外,还允许动态绑定作用域(绑定执行环境)。

a = 1
eval('a + 1') #  (evaluates to 2)

# evaluating within a context
def get_binding(a)
  binding
end
eval('a+1',get_binding(3)) # (evaluates to 4, because 'a' in the context of get_binding is 3)
class Test; end

Test.class_eval("def hello; return 'hello';end") # add a method 'hello' to this class
Test.new.hello                    # evaluates to "hello"

3 什么是 REPL

REPL(read-eval-print loop)通俗的讲就是交互式执行环境。比如 unix shell 中的命令就是 repl,JavaScript 在 Chrome console 中也可以交互式执行,python 的 IPython,ruby 的 irb。

repl 的实现方式:

(loop (print (eval (read))))

现在流行的一个观点是,“不能 REPL 的语言都是垃圾语言”,虽然话很偏激,但确实说明了 REPL 对一门编码语言的意义,REPL 让编程语言更友好,能让程序员更方便、高效的去学习和理解这门语言。

像 Python,Ruby 都是原生支持 REPL 的语言。一些原生不支持 REPL 的语言,也在积极的通过库或者框架的方式去间接支持 REPL。

Java 也在往 REPL 方向努力着,比如 JDK 9 中的 JShell,不过体验一般。

猜你喜欢

转载自blog.csdn.net/antony1776/article/details/84201188
今日推荐