Lua 架構 The Lua Architecture

轉載自:http://magicpanda.net/2010/10/lua%E6%9E%B6%E6%9E%84%E6%96%87%E6%A1%A3/

Lua架構文檔(翻譯)

102010

前段時間翻譯了lua官方關於lua5架構設計的一份文檔,如今分享給你們。html

注意:全部版權都歸lua官方全部,本人僅將其翻譯爲中文,以方便中文閱讀者。翻譯中出現任何錯誤致使的結果,本人不負任何責任。ios

若是有任何翻譯錯誤,以及意見與建議,請email本人。郵件地址:ice_ok@163.com。git

轉載請註明原做者、翻譯者與出處。算法

The Lua Architecture

Lua架構

Advanced Topics in Software Engineeringexpress

軟件工程中的高級主題編程

Mark Stroetzel Glasbergapi

Jim Bresler數組

Yongmin ‘Kevin’ Cho數據結構

Introduction

介紹

Lua is a powerful light-weight programming language designed to extend applications.閉包

lua是一種輕量級的編程語言,其設計目的在於擴展應用程序。

Lua started as a small language with modest goals.  The language has grown incrementally. As a result, Lua has been re-architected and rewritten several times in the past ten years. The original functional requirements and motivation of the architecture were documented in the paper 「Lua-an extensible extension language」 [1]. A few other versions of the language were briefly described in 「The Evolution of an Extension Language: A History of Lua」 [3].

lua起始於一個目標適中的簡單語言,而後不斷成長。由此,lua在過去10年中被從新設計、從新編寫了屢次。模型的最初功能需求與驅動記錄於 「Lua-an extensible extension language」文檔中。lua的一些其餘版本在「The Evolution of an Extension Language: A History of Lua」有簡單的描述。

The architecture and implementation was created and is maintained by Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo at the Computer Graphics Technology Group of the Pontifical Catholic University of Rio de Janeiro in Brazil (PUC-Rio).

lua的架構與實現由Roberto Ierusalimschy,Waldemar Celes和Luiz Henrique de Figueiredo建立與維護,於巴西 – 里約熱內盧 - Pontifical Catholic大學的計算機圖形技術組。

Lua’s implementation consists of a small library of ANSI C functions that compiles unmodified in all known platforms. The implementation goals are simplicity, efficiency, portability, and the ability to run on small devices with limited capabilities. These implementation goals resulted is a fast language engine with small footprint, making it ideal in embedded systems.

lua的實現包含一個很小的庫,這個庫由一些在全部平臺一致的ansi c函數組成。這樣實現的目的在於簡單、高效、輕便,並能運行於兼容性有限的微小設備上。實現這些目標後獲得的就是一個資源佔用很小的高速語言引擎,適於系統嵌入。

This paper reconstructs and documents the architecture of Lua version 5.0.2. Lua 5.0.2 contains approximately 25,000 lines of source code.  The code base uses an instance of the compiler reference model, has several identifiable patterns, and is divided into clearly defined modules such as the code interpreter, parser and virtual machine.

這份文檔重建並文檔化了lua V5.02的架構。lua V5.02包含大約25,000行源碼(YoungMan注:lua V5.1.3大概是17,000行)。這些代碼基於編譯引用模型實例的應用,有機種固定模式,並劃分紅一些定義清晰的模塊,如,代碼解釋器,語法分析器, 虛擬機。

The language is being used in several projects at Tecgraf, PUC-Rio, University of Illinois at Urbana-Champaign and in several industry companies such as Microsoft, LucasArts Entertainment, and others.

Lua正用於Tecgraf, PUC-Rio, University of Illinois of Urbana-Champaign的數個工程中,在一些商業公司中,如,微軟,lucasArts娛樂等也有應用。

Architectural Requirements

架構需求

Lua’s main quality attributes, which are simplicity, performance, flexibility, and portability, were driven by the business requirements of projects developed at Tecgraf. Tecgraf is a Computer Graphics Technology Group created in May 1987 in a partnership between PETROBRAS (the Brazilian main oil company) and the Pontifical Catholic University of Rio de Janeiro – PUC-Rio. Its purpose is to develop, establish, and maintain computer graphics and user interface software for technical and scientific applications.

lua的主要質量屬性,也就是,簡明性,性能,靈活性,輕便性,主要由Tecgraf小組開發的數個工程需求驅動。Tecgraf小組由PETROBRAS(巴西主要的石油公司)公司與PUC-Rio大學合做於1987年建立,是一個計算機圖形技術小組。

Business Drivers

業務驅動

The first project in which Lua was used needed to represent data for graphic simulators. This rudimentary ancestor of Lua was not a script language, but a data representation language. Because graphic information is naturally large, high performance was the first attribute to be considered. When users began to demand more power from this data representation language - such as the use of boolean expressions, conditional control and loops - it was clear that a true programming language was needed.

Lua應用的第一個工程須要爲圖形模擬器表示數據。Lua的最初雛形不是一個腳本語言,而是一個數據表示語言。由於圖形信息天生就很龐大,因此高性 能是首要考慮的目標。當用戶對這種數據表示語言提出更多功能需求時,例如,boolean表達式的使用,條件控制與循環等,結果就十分清晰了:咱們須要的 是一門真正的編程語言。

Data description played an important role in the evolution of Lua as different projects at Tecgraf were adopting Lua. Therefore, Lua had to be easily customizable for each application. Lua adopted the use of semi-structured data in the form of associative arrays. Moreover, metamethods (explained later) were introduced in the language to provide additional flexibility to data access.

因爲Tecgraf的多個工程都採用Lua,數據描述在lua的演化中扮演了十分重要的角色。由此,Lua必須很容易適應各類應用程序。Lua採用 了關聯數組形式的半結構化數據(YoungMan注:也就是lua中的table)。更重要的是,元方法(後面詳細解釋)被加入到語言中以對數據訪問提供 額外的靈活性。

Portability was an important issue for Lua. At the time, Tecgraf’s main client, PETROBRAS, required all developed systems to be capable to run on a wide range of computers systems.

輕便性在lua中十分重要。在當時,Tecgraf的主要客戶——PETROBRAS要求全部開發系統必須對各類範圍普遍的計算機系統兼容。

Finally, the business drivers also originated other functional requirements such as concurrency support, string pattern matching, garbage collection, and namespaces for modules. Most of these functionalities were added at a later point in the evolution of the language.
最後,業務驅動也源於其餘一些功能性需求,例如併發行,字符串模式匹配,垃圾收集,以及模塊的命名空間。這些功能大多數是在lua以後的演化過程當中逐步添加進來的。

Quality Attributes and Tactics

質量屬性與策略

As a result of its business drivers, Lua’s main quality attributes were not only performance, portability, and extensibility, but also simplicity, availability, and compactness .
因爲是業務驅動,lua的主要質量屬性不只僅是性能,輕便性,與擴展性,還包括簡明性,實用性,與緊密性。
The development process of Lua played an important role in assuring that the quality requirements were met. New features could only be added to the language only when all committee members reached unanimity. This helped keep Lua’s simplicity, which is generally considered Lua’s most important asset. Lua’s compactness is a consequence of its simplicity. As a result, extensibility became essential to the language.
Lua的開發進程中很是看重是否達到這些質量需求。只有委員會成員達成一致,Lua才能添加新的語言特性。這幫助保持了lua的簡明性,而簡明 性大致上被認爲是lua最爲重要的方面。lua的緊密性是其簡明性的結果。由此,對lua來講擴展性變得不可或缺。(YoungMan注:也就是說,爲了 保證lua的簡明性與緊密型,lua核心的內容不多,毫不輕易添加內容;爲了避免侷限lua語言的功能,其擴展性就變得很是重要,以提供用戶定義的功能擴 展)。
Extensibility has been achieved by adopting several mechanisms such as data representation of C/C++ pointers (called userdata), dynamic loading of external modules, namespaces, and metamethods. Metamethods allow user-defined functions to be invoked when an associative array or a userdata variable is accessed. This allows customization of data accessing through the definition of user-defined operations. This mechanism provides flexibility to the language without making it complex.
擴展性已經經過一些方法完成了,這些方法包括如,C/C++指針的數據表示法(稱之爲用戶數據userdata),動態加載外部模塊,名字空 間,以及元方法等。元方法容許在訪問關聯數組或者用戶數據變量時引入用戶自定義函數。這就容許經過自定義用戶操做來自定義數據訪問過程。這些方法使得 Lua靈活卻不復雜。
Thanks to Lua’s flexibility, several individual libraries add functionality to Lua.  Some examples include: user interface support [14], socket support [15], and middleware support [16].
得益於Lua的靈活性,幾個獨立的庫爲Lua添加了許多功能。例如:用戶接口支持,socket支持,中間件支持等。
One tactic used to improve Lua’s performance was the use of a virtual machine. A virtual machine provides a way to speed execution time because it allows precompiled code to be forwarded directly to it, therefore bypassing the lexical and syntactical analysis. This architecture was pioneered in Smalltalk (Goldberg–Robson 1983; Budd 1987) from which the term bytecode is borrowed.
虛擬機的使用是爲改進lua性能而採用的一大策略。虛擬機提供了一種方式加速執行時間,即,它容許直接訪問預編譯代碼,也就省去了詞法與語法分析的時間。這種架構始於smalltalk中,smalltalk就是訪問一段段的字節碼。
Lua’s portability is archived by using only ANSI C code. But even though the standard was followed closely, great care had to be taken to avoid portability problems. The heterogeneous community of users has been helpful identifying compilers discrepancies and solving compiling issues throughout the language’s evolution.
lua的輕便性經過僅使用ansi c達成。但儘管徹底遵照標準,仍然必須很是當心以免輕便性方面的問題。在lua的演化中,各類各類的用戶社區對識別編譯器的差別性、解決編譯的各類問題提供了很是多的幫助。
Availability has been achieved as a consequence of compactness, the use of good implementation standards, and a big set of tests to catch bugs.
實用性則是語言緊密性,充分利用好的實現標準,以及應用大量測試來查找bug後獲得的結果。

Lua Features

Lua特性

Lua offers a wide variety of programming functionalities such as loops, scope, function calls, arithmetic calculations, string pattern matching, error handling (exception like), coroutines, garbage collection, debugging mechanisms, comprehensive C API, OS facilities, input and output functions, and more.
Lua提供了普遍的編程功能,如循環,做用域,函數調用,數學計算,字符串匹配,錯誤處理(相似異常),協程,垃圾收集,debug方法,綜合多樣的C API,OS操做,IO功能,等等。
Following its objective of simplicity, Lua defines a reduced number of data types. Although the number of data types is reduced, they are powerful enough to accomplish all of Lua’s objectives. Below we present and describe Lua’s data types.
根據Lua簡明性的目標,lua僅定義幾種簡單的數據類型。儘管數據類型不多,但足夠強大以完成lua的全部目標。下面是lua中數據類型的表示與描述。
  • stringrepresents arrays of characters. Lua is 8-bit clean: Strings may contain any 8-bit character, including embedded zeros (‘\0′).
  • 字符串           表示字符數組。lua是8位的:字符串可能包含任意8位字符,包括轉義0(‘\0′)。
  • numberis defined by default at compile time as the double type in C. This simplifies the use of number types in Lua by allowing the user to represent just about any number: integer, positive, negative, and floating point. In addition, user may change the number type of Lua in compile time.
  • 數值                默認於編譯期在C代碼中被定義爲double類型。這容許用戶表示任意類型的數據,如,整型,正數,負數,浮點數,由此簡化了數值類型在lua中的使用。此外,用戶也能夠在編譯期改變其數值類型。
  • nil is a special empty value.
  • nil          是一個特別的空值。
  • booleanis defined as true, or false.
  • boolean           定義爲true或者false。
  • functionis a first-class value. It can be either a Lua or C function and can be stored in variables.
  • 函數               是一個一類值。它能夠是存儲在變量中的lua或者C函數。
  • userdataallows arbitrary C data to be stored in variables.
  • 用戶數據           容許在變量中任意存儲C數據。
  • thread represents independent thread of execution and is used to implement coroutines.
  • 線程              表示獨立執行的線程,用以實現協程。
  • table is the fundamental data structure mechanism defined by Lua. Lua tables are associative arrays that allow the user to index and store any other Lua data type. This allows the user to create many types of data structures such as lists, trees, and graphs.
  • 表                  是lua定義的基礎數據結構。lua tables是關聯數組,容許用戶索引和存儲其餘lua數據類型。這容許用戶建立各類類型的數據結構,例如,線性表,樹,圖等。
One important design consideration is Lua’s ability to classify and represent data.  Lua is a weakly typed language; this means that variables do not have types, but the variable’s values do.
設計考慮中很重視lua分類和表示數據的能力。lua是弱類型語言,這意味着變量沒有類型這一律念,但變量的值有。
Among Lua’s data types are tables and userdata. Lua uses the table and userdata types to support application specific structures. Tables are really associative arrays [6], an abstract data type that behaves similarly to arrays but allows anything to be a key or a value. This structure allows several data structures to be represented such as trees, graphs, or even XML files.
Table和userdate是lua數據類型之一。Lua使用table和userdate類型來支持應用程序特定結構。Table其實是 關聯數組,一種抽象的數據結構類型,相似於數組,但容許任意的內容做爲其項的鍵與值(key & value)。這種結構能夠表示各類數據結構,例如樹,圖,甚至XML文件。
In addition, Lua allows the semantics for both userdata accesses and table accesses to be altered through metamethods. Metamethods enable applications to override the default logic of data access, supporting for example the implementation of object oriented mechanisms [18].
此外,lua容許經過元方法切換訪問table、userdate的語義。元方法容許應用程序覆蓋對默認邏輯數據的訪問,支持例如面向對象方法的實現。
Changing table access policies enables the user to reflect a C++ variable in Lua and translate Lua method calls to C++ method calls. This mechanism is used extensively by tolua [13], a tool that helps creates C and C++ bindings to Lua. Finally, Lua allows metamethods to be changed during execution, adding even more flexibility to the mechanism.
改變table訪問策略使得用戶能夠在lua中表示C++變量,吧lua方法調用轉換成C++方法調用。這種方法在tolua中用的不少。tolua是幫助建立C/C++對lua綁定的工具。最後,lua還容許執行時改變元方法,更增強了這種方法的靈活性。
Another characteristic of Lua function calls is that function parameters are passed as references, so function calls are fast. Nonetheless, parameters cannot be changed inside functions; as a result, the number of function return values becomes limited. Lua solves this issue by allowing multiple values to be returned in function calls. lua函數調用的另外一個特性是函數參數是引用傳遞的,因此函數調用很快。儘管如此,參數不會在函數內部被修改;所以,函數返回值的個數也是有限的。但 lua容許在函數調用中返回多個值,由此解決了這個問題。(YoungMan注:也就是說,lua沒法使用相似C函數在參數中獲取多餘一個的返回值的方 式,但容許直接返回多個結果)。

Architectural Solution

架構解決方案

In this section we describe the architecture of Lua. This text describes first how Lua receives and interprets a script file. Next, we present the internal module decomposition of Lua and how each module interacts with each other. Finally, we describe most of Lua’s subsystems.
在這一部分,咱們描述lua的架構。這些文本首先描述lua如何接收、解釋腳本文件。而後,咱們展現lua內部模塊的劃分,以及各模塊之間如何相互通訊。最後,咱們描述lua的重要子系統。

Lua: An Embedded Script Language

Lua:一種嵌入式腳本語言

Although Lua offers a stand alone command line interpreter, Lua is designed to be embedded in an application. Applications can control when a script is interpreted, loaded, and executed. They can also catch errors, handle multiple Lua contexts, and extend Lua’s capabilities.
儘管lua提供獨立的命令行解釋器,lua主要設計用於嵌入到應用程序中。應用程序能夠控制腳本的解釋,加載,執行,固然也能夠捕獲錯誤,處理各類lua上下文,而且擴展lua的功能。
The process of initializing Lua and loading a script is depicted in Figure 1.
lua初始化,而後加載腳本的過程以下圖1所示。

Figure 1 : process of initializing Lua and loading a script file
圖1:lua初始化與加載腳本的過程
Four steps are necessary to load and execute a Lua script.  First, a state of the Lua interpreter must be created. This state is passed on to all functions of Lua’s C API, including the calls done in the following steps. Second, the application embedding Lua registers all libraries that extend Lua.  Next, scripts provided by the application are parsed and instructions that the virtual machine can execute are generated. These instructions are referred to as bytecodes. Finally, the bytecodes are forwarded to the virtual machine for execution.
加載而後執行lua腳本須要4個步驟。首先,要建立一個lua解釋器的狀態(lua state)。這個狀態會被傳遞給Lua C API的全部函數,包括接下來的步驟中調用的函數。第二步,嵌入lua的應用程序會註冊全部的庫以擴展lua。接下來,lua對應用程序提供的腳本進行語 法分析並生成虛擬機能夠執行的指令。這些指令稱之爲字節碼。最後,字節碼被送入虛擬機執行。
The first step to loading and executing a script is creating a Lua interpreter reference.  This step consists of initializing a lua_State structure by calling lua_open.  The lua_State structure is necessary because Lua offers a reentrant API and does not use any global variable.  As a result, an application may create multiple instances of the Lua interpreter.
加載與執行腳本的第一步是建立lua解釋器的引用。這一步主要是調用lua_open初始化lua_State結構體。lua_State結構體必須的,由於lua提供可重入的api,而且不須要使用任何全局變量。正因爲此,應用程序能夠建立多個lua解釋器的實例。
Next, the application needs to register libraries available to Lua programs.  Lua supports a default set of libraries for target applications.  Applications may expand or contact the list of libraries available to Lua programs by controlling which libraries are registered.  This allows applications to customize the library functions available to Lua applications.
接下來,應用程序須要註冊可用的庫到lua程序中。lua支持爲目標應用程序使用默認的庫集合。應用程序也能夠經過控制庫的註冊來擴展或將可用的庫列表關聯到lua程序中。這使得應用程序能夠爲lua程序自定義庫的可用功能。
Afterwards, the Lua interpreter needs to obtain bytecodes to execute. At this point, there are two possible scenarios: precompiled Lua bytecodes are loaded or a Lua script is loaded. When loading a script, Lua uses standard lexer, parser, and bytecode generation components to precompile the program.  These components behave like Pipes and Filters [11] by passing data to each other sequentially and incrementally.  Because each of these components has a significant impact on performance, Lua needs to execute these components as quickly as possible.  Therefore, Lua does not use automated code generation tools such as lex or yacc [17]; instead, the Lua implementation has a hand-written parser and lexer.
以後,lua解釋器須要獲取字節碼以執行腳本。此時,有兩種可能的場景:預編譯lua字節碼被加載或者lua腳本被加載。若是加載腳本,lua 使用標準的詞法、語法分析器,以及字節碼生成組件來預編譯程序。這些組件的行爲相似於管道或者說過濾器,序列化地、增量地互相傳遞數據。因爲各個組件的性 能都很是關鍵,lua必須儘量快地執行這些組件。所以,lua不能使用自動代碼生成工具,例如,lex或者yacc;取而代之的是,lua實現中有手工 編寫的語法、詞法分析器。
Finally, Lua needs to execute the bytecodes.  The virtual machine kernel contains a loop that reads and executes a virtual machine instruction.
最後,lua須要執行字節碼。虛擬機內核包含一個讀取和執行虛擬機指令的循環。

Module Decomposition

模塊劃分

Lua is divided in subsystems to support its requirements. These modules include an application loader, library loader, a public API, auxiliary libraries, several modules to support the virtual machine, and several modules to support translating Lua script into bytecode.  A static view of Lua’s modules and relationships between them is depicted in Figure 2. In addition, the picture shows the implementation file of each module.
lua劃分爲子系統以支持其需求。這些模塊包括應用程序加載器,庫加載器,開放API,輔助庫,幾個支持虛擬機的模塊,以及幾個將lua腳本轉換爲字節碼的模塊。lua模塊及其之間的關係的靜態視圖以下圖2所示。此外,這個圖也說明了每一個模塊的實現文件。

 

Figure 2 : Lua Module Decomposition
圖2:lua模塊劃分
Lua’s module decomposition helps Lua address its quality and functionality requirements.  In particular, the module decomposition helps Lua maintain its compactness goals because it allows detachment of modules from the normal distribution.   For example, Lua separates core platform code and auxiliary code by placing them into different libraries.  As a result, applications embedding Lua are not required to link the auxiliary library.  The module decomposition also allows applications to reduce Lua’s footprint by removing the parser subsystem if the application only needs to execute precompiled programs.
Lua模塊劃分幫助lua肯定其質量和功能需求。特別是,模塊劃分幫助lua保持其緊密性目標,由於,它容許把模塊從正常發佈版本中分離出來。 例如,lua經過將核心平臺代碼和輔助代碼放置與不一樣的庫中來分離它們。由此獲得的結果是,嵌入lua的應用程序不強制須要連接輔助庫。這種模塊劃分容許 應用程序減小lua的印記,好比,若是應用程序僅須要執行預編譯程序,就能夠將語法分析器去除掉。(YoungMan注:就是說能夠儘可能少地包含應用程序 須要的lua模塊)
Another advantage of Lua’s module decomposition is that it minimizes the dependencies between external applications and Lua. The public API presents a facade [11] that allows applications to use Lua without knowledge of its internal decomposition. This allows the Lua team to make several types of changes without breaking compatibility with existing applications. As a result, applications can often upgrade the version of the Lua interpreter without making any source code changes.
lua模塊劃分的另外一好處是它最小化了外部應用程序與lua之間的依賴關係。這些公開的API提供了一整套接口,容許應用程序在不知道lua內 部劃分時也能使用lua。這容許lua團隊作各類改變,卻不破壞Lua與已有程序的兼容性。由此,應用程序能夠常常性升級lua解釋器的版本,去不須要作 任何代碼修改。(YoungMan注:簡單來講,就是lua封裝得很好,能夠不改變接口,而改變實現。內部實現的改變不會對已有外部代碼形成影響。)
However, the public API is difficult to use. The auxiliary library exposes a simplified API to applications that is easier to use than the public API.  For example, the auxiliary library provides functions that load a Lua script or precompiled file from disk. The auxiliary library is powerful enough to address the requirements of most applications that embed Lua. However, applications still have the ability to use the core API when the auxiliary library is not sufficiently powerful.
儘管如此,這些公開的API使用起來仍是有些困難。輔助庫爲應用程序提供了一套更簡單、更易於使用的API。好比,輔助庫提供一個函數用於從磁 盤加載腳本或者預編譯它。輔助庫至關強大,能夠知足絕大多數嵌入lua應用程序的需求。然而,應用程序在輔助庫沒法知足需求時仍是應該使用核心API的。
The public API interacts with subsystems to perform operations requested by the application.  For example, the public API interacts with the parser subsystem to convert Lua scripts to bytecodes. The parser subsystem consists of a lexer, parser, and bytecode generator.
這些公開的API與子系統交互以提供應用程序請求的操做。例如,公開API與語法分析器子系統交互以將lua腳本轉換成字節碼。
Another important subsystem is the virtual machine.  The virtual machine helps Lua achieve its performance requirements. Its modules consist of a virtual machine kernel, garbage collector, debugging interface, and others.
另外一個重要的子系統是虛擬機。虛擬機幫助lua達到性能方面的需求。其模塊包括一個虛擬機內核,垃圾收集器,debug接口,等等。
The virtual machine increases performance by decoupling language syntax from application execution semantic, allowing faster loading of pre-compiled scripts. For this purpose, the Lua distribution offers an external compiler that allows translation of Lua scripts to bytecode form. This bytecode form also serves as code scrambling, hiding the code source in the application’s final distribution.
虛擬機將lua語法與應用程序執行語義解耦合,這樣能更快地加載預編譯後的腳本,由此lua虛擬機的性能也獲得了提高。爲達到此目標,lua發佈版本提供了外部編譯器容許將lua腳本編譯成字節碼的形式。這種字節碼也用於在應用程序的最終發佈版本中混淆、隱藏lua源碼。
Lua also uses several utility modules to meet its requirements. For example, Lua has an error detection module that allows errors to be handled in a centralized manner. The module allows the execution of C function in  protected mode.  A function running in protected mode can throw an exception if it encounters an error.  When a function throws an exception, control returns immediately to the caller of the protected mode function.
lua也使用一些工具模塊以知足需求。例如,lua有一個錯誤探測模塊,容許集中處理錯誤。這個模塊容許C函數以保護模式執行。運行於保護模式的函數在遇到錯誤時能夠拋出一個異常。當函數拋出異常時,控制權就返回給以保護模式調用函數的調用者。

Subsystems

子系統

Lua is divided into subsystems that separate functionality. We have explained how the subsystems work together; now we explore in more detail some of Lua’s subsystems.
lua根據功能劃分子系統。咱們已經解釋過子系統如何一塊兒運行;如今咱們探討更多lua子系統的細節。

Parser

語法分析器

The objective of the Lua parser subsystem is to convert Lua scripts to bytecodes that the virtual machine will eventually execute. Therefore, the parser subsystem consists of a lexer, a parser, and a bytecode generator.
lua語法分析器子系統的目標是將lua腳本轉換成字節碼,而字節碼則是虛擬機最終執行的代碼。因此,語法分析器子系統包括一個詞法分析器,一個語法分析器,和一個字節碼生成器。
The lexer and parser follow the compiler reference model. In this model, the lexer is responsible for obtaining tokens, which are separate identifiable parts of the script file such as constants, operators, keywords, and others. The parser is responsible for analyzing the structure in which the tokens are disposed in the file in order to compose commands. In addition, the parser can generate error messages for invalid command constructions.
詞法分析器和語法分析器使用編譯引用模型。在此模型中,詞法分析器負責獲取標誌符,也就是腳本文件中分開的可確認的部分,例如,常量,操做符,關鍵字等等。語法分析器負責分析文件中標誌符放置的結構以組成命令。
The Lua parser uses only one-pass to maximize performance. This is viable because Lua does not perform type checking because all variables are untyped. In addition, function existence and prototype verification of calls are not checked during parsing. However, this solution causes problems during the programming process because many errors are only caught during run-time.
lua語法分析器使用一次遍歷以最大化性能。這是可行的,由於lua並不進行類型檢查——全部變量都是無類型的。此外,函數存在性與調用的原型驗證在語法分析中也不檢查。可是,這種解決方案也致使程序運行時存在問題,由於許多錯誤只有在運行時纔會被捕獲到。
The parser subsystem defines the concept of a chunk. A chunk is a unit of execution which consists of a series of command statements. The parser is designed to work on one chunk at a time. Chunks can be provided by the host program in the form of a file or a string. When Lua script is supplied incrementally (for example by providing a sequence of separate strings to be interpreted), a new chunk is created every time.  In each of the chunks the user can specify direct statements, functions, local variables, and return values.
語法分析器子系統定義了一個稱之爲代碼塊(chunk)的概念。代碼塊是代碼執行的單位,包含一系列命令語句。語法分析器一次處理一個 chunk。代碼塊能夠以文件或者字符串的形式,由宿主程序(YoungMan注:lua被嵌入到應用程序中,因此應用程序也能夠被稱爲宿主程序,lua 稱爲寄生程序。)提供。當腳本被一點一點提供(例如,一組各自獨立的字符串須要被解釋)的時候,每次都建立一個新的塊。在每個塊中,用戶能夠直接指定語 句、函數、局部變量,或者返回值。
The parser will generate bytecode for each chunk that it interprets. Chunks can then be passed on to the virtual machine for execution. This can be passed directly through memory or each chunk can be persisted to disk as precompiled bytecodes for later execution in the virtual machine.
語法分析器爲它解釋的每個代碼塊生成字節碼。而後塊能夠傳入虛擬機中執行。這能夠是直接經過內存傳遞給虛擬機;或者也能夠做爲預編譯字節碼保存到磁盤中,等待之後虛擬機執行使用。

Virtual Machine

虛擬機

The virtual machine subsystem is responsible for executing bytecodes generated by the parser subsystem.  Because most processor time is spent in the virtual machine subsystem after the Lua script is loaded, the design of the virtual machine subsystem has a large impact on overall system performance. Furthermore, the virtual machine subsystem cannot be removed from a minimal Lua interpreter. As a result, the virtual machine subsystem needs to be compact and have good performance.
虛擬機子系統負責執行由語法分析器子系統生成的字節碼。因爲在lua腳本加載以後,處理器的時間大部分都花費在虛擬機子系統上,虛擬機子系統的設計對總性能有很是大的影響。除此以外,虛擬機子系統不能從最小lua解釋器中移除。所以,虛擬機子系統必須緊密且性能良好。
The virtual machine kernel can read and execute bytecodes. To support this functionality, the virtual machine kernel continuously loops for the next operation to execute. The loop identifies the type of operation and performs an instruction-specific task to execute it.  Several modules, such as the garbage collector, table, and closure modules, are invoked by this loop to assist the virtual machine kernel.
虛擬機內核能讀取和執行字節碼。要支持這項功能,虛擬機內核不斷循環以執行下一個操做。這個循環識別操做的類型而後運行特定指令以執行程序。這個循環會引用到幾個模塊,例如垃圾收集器,table,以及閉包模塊,以輔助虛擬機內核。
Bytecode operations have been carefully designed to ensure subsystem compactness and performance. All instructions are 32-bit long and can contain from one to three arguments. The arguments are typically denoted as A, B, and C. Some instructions combine the B and C into a bigger argument called Bx. All opcodes have a constant length.
字節碼的相關操做設計得十分細緻,以確保子系統的緊密性與性能。全部指令都是32位長,有1~3個參數。參數以A、B、C表示。部分指令將B和C合成一個大的參數稱之爲Bx。全部操做碼都長度固定。
The virtual machine organizes the data that it must handle in a global table, a local constant table, and several registers . The purpose of the global table is to store values that be accessed anywhere in a Lua script.  The constant table stores constant data (such as strings, numbers, etc.) so that virtual machine operations do not need to directly use constant values. Data in the constant table is indexed by position.  Multiple references to the same constant have the same position in the constant table.
虛擬機將其須要處理的數據組織在一張全局表,一個局部常量表,和一些寄存器中。全局表的目的是存儲腳本中任何地方均可能用到的數據。常量表存儲 常量數據(如,字符串,數值,等),這樣虛擬機不須要直接使用常量值。常量表中的數據經過位置進行索引。對同一常量的屢次引用會指向常量表的同一位置。
Stacks are used during function calls and are created for each closure. A closure is basically an instance of a function. Local variables defined in a closure reside in the closure’s corresponding stack for the duration of the closure.  Moreover, designated variables that reside in the outer scope (usually called upvalues) can be accessed. When the function is completed, the closure is finished and the corresponding stack is cleaned. In the next section we explain some of the problems that need to be addressed when a function finishes.
每個閉包都會建立一個棧,而後在函數調用中使用它。一個閉包基本上是一個函數實例。在整個閉包存在的過程當中,在閉包中定義的局部變量將一直存 在於閉包相應的棧中。此外,存在於做用域之外的指定變量(也稱爲非局部的變量,即upvalue)也能夠被訪問到。當函數結束的時候,閉包也就結束,相應 的棧也會被清理。在下一節,咱們會解釋函數結束的時候一些須要說明的問題。
Finally, in appendix A we describe two examples of how a Lua script is translated into virtual machine instructions. Additional information about the Lua virtual machine and its bytecodes is presented in the document 「A No-Frills Introduction to Lua 5 VM Instructions」 [20].
最後,在附錄A中,咱們描述了兩個例子,說明lua腳本是如何轉換成虛擬機指令的。更多關於lua虛擬機與其字節碼的信息保存於文檔「A No-Frills Introduction to Lua 5 VM Instructions」 [20]中。

Closures

閉包

Lua defines the scope of variables as global or local. Global variables can be accessed anywhere during the execution of a script. The scope of local variables begins at the first statement after their declaration and lasts until the end of the innermost block that includes the declaration. Variables that are in the outer scope can always be accessed from the inner scope.
lua定義變量的做用域爲全局的或者局部的。全局變量在腳本執行中任意時刻均可以訪問。局部變量的做用域起始於聲明語句,直到包含聲明的最裏層代碼塊結束爲止。外層做用域聲明的變量在內層做用域總能夠訪問。
Functions in Lua are first class values. This means that functions can be assigned to variables just like any other value. In addition, functions can be defined inside other functions and returned as values. As a result, nested functions can be executed even after their containing block has finished executing. Because the nested function can access data outside of its local scope, Lua cannot discard a block’s variables after it finishes executing.
lua中的函數是第一類值。這意味着函數能夠能夠做爲變量賦值,就像其餘值同樣。此外,函數能夠在其餘函數內部定義,而且做爲值返回。這樣,嵌 套函數即便在他們的包含塊結束執行以後也能夠被執行。因爲嵌套函數能夠訪問其內部做用域之外的數據,lua不能在塊結束以後就丟棄塊中的變量。
Usually, a stack holds local variables; when the function call ends, the values are removed from the stack and destroyed. Because of Lua’s scope visibility rules, these variables cannot be immediately released. Lua solves the problem by using a stack to maintain local variables when the function is executing. In addition, Lua keeps a linked list of pending variables that will be checked for possible references after the block executes. After the block executes, Lua checks which local variables are still needed. Finally, variables that are still referenced are moved from the stack to the heap.
通常來講,棧中保存局部變量;當函數調用結束,這些值就從棧中移除並銷燬。因爲lua的做用域可見性規則,這些變量不能當即釋放。爲了解決這個 問題,lua在函數執行中使用棧來保持局部變量。此外,lua保持對不肯定變量的引用列表,在塊執行結束後會對這些不肯定變量檢查是否可能存在引用作檢 查。
The left side of Figure 3 presents the internal Lua organization during a function call. Both nested and enclosing functions access local variables from the stack to guarantee consistency. The right side of Figure 3 shows what happens after the function ends: the stack removed the function variable and moved it to the heap. This allows more than one nested function to access external local variables of outer scopes.
下圖3左側表示在函數調用中lua的內部組織結構。嵌套的和封閉的函數都從棧中訪問局部變量以保證一致性。圖3的右側展現了,在函數結束後將會發生的事情:棧移除函數變量,並將其挪入堆中。這樣就容許不止一個嵌套函數訪問非局部的變量。

Figure 3 : Lua Closures
圖3:lua閉包
The fact that Lua allows local function variables to persist through nested functions (even after the outer function has ended) provides Lua with an additional benefit. Lua can act in an object-oriented style by allowing applications to restrict variable accesses to specific functions.
因爲lua容許局部函數變量貫穿於嵌套函數(即便在外部函數結束以後)存在(YoungMan注:也就是非局部的變量),這也給Lua帶來一些額外的好處。

Garbage Collector

垃圾收集器

Lua uses a generic mark and sweep algorithm to implement garbage collection.  The amount of data consumed during the execution of a Lua script is tracked.  When a threshold value is reached, the garbage collector frees all data that is no longer referenced. However, this approach has a drawback. The garbage collection operation can occur at any time, creating problems when real-time applications use Lua.  Furthermore, the garbage collector is executed very frequently for applications that use a lot of memory. For these reasons, major changes are expected for the garbage collector in Lua version 5.1.
Lua使用一個泛型的標記與清掃算法實現垃圾收集。lua會跟蹤在腳本執行中被銷燬的數據。當達到閥值時,垃圾收集器就會釋放再也不引用的全部數 據。然而,這種方法有一個缺點。垃圾操做會在任意時刻進行,這樣在實時程序使用Lua時就會帶來問題。更嚴重的是,垃圾收集器在消耗大量內存的應用程序中 執行十分頻繁。因爲這些緣由,預期在lua5.1中垃圾收集器是修改的重點。

Table

Tables are the only data structure in the Lua language. Tables are a powerful construct that maintains language simplicity and generality. Internally, a table is implemented as two separate parts: a hash table and an array.
table是lua語言中惟一的數據結構。table是提供語言簡單性與普遍性的強大結構。就內部實現來講,一個table由兩個獨立的部分組成:一個hash表和一個數組。

Non-negative integer keys are all candidates to be kept in the array part. The actual size of the array is the largest index value such that at least half the slots between zero and this value are in use.

非負整數鍵將被存放在數組部分。數組的實際大小是最大索引值,這樣0與最大索引值間至少一半的槽位都在使用中。

The hash function uses a chained scatter table with Brent’s variation [21]. If a table element is not in its main position (i.e. the position given by the hash function) then a colliding element must be in the objects main position. In other words, there are collisions only when two elements have the same main position. Because of this, the load factor of these tables can be 100% without performance penalties.
哈希表使用Brent變種的鏈表保存不連續的數據。若是表中元素不在其主位置(例如,hash函數給定的位置)那麼此處一定是存儲了一個衝突對象。換句話說,當兩個元素具備同一主位置時,就產生了衝突。所以,這些表的負載係數100%沒有性能損耗。
The data structure is very efficient. Nevertheless, like all hash tables, its performance depends on the distribution of hashes.  So far, the Lua community has not reported any problems with string hashes.
這種數據結構很是高效。不只如此,像全部的hash表,其性能依賴於哈希分佈。到目前爲止,lua社區沒有反饋說字符串哈希存在問題。
Figure 4 shows an example of a Lua table which is composed of a hash table and an array.  As shown in Figure 4, the fifth numeric value of the array can either be stored in the hash table or in the array. Numeric keys which do not fall within the capacity of the array part are handled normally. This mechanism is transparent to other Lua modules.
圖4展現了一個例子,說明lua是由hash表和一個數組組成。如圖4所示,數組中的第五個數值元素或者存於hash表中,或者存於數組中。散落在數組容量以外的數值鍵也會被正常處理。這種方法對lua其餘模塊徹底透明。

Figure 4 : Example of a Lua table internal organization
圖4:lua表內部組成的示例

Standard Library

標準庫

Lua includes a standard library containing functionality needed by several applications such as string pattern matching, file I/O, and basic math support. In addition, the standard library interfaces with the Lua runtime to help support several language features such as coroutines and tables.  For more information, see the Lua reference manual [7].
lua包括一個標準庫,其包含一些應用程序須要的功能,例如字符串模式匹配,文件I/O,以及基本的數學支持。此外,標準庫會與lua運行時進行交互以幫助支持一些諸如協程、表之類的語言特性。更多的信息請閱讀lua參考手冊。

Dynamic Libraries

動態庫

Dynamic Library support provides a key mechanism to extend Lua. It allows applications that embed Lua to expand and reduce the functionality available to scripts. As a result, dynamic libraries help Lua achieve its compactness and flexibility requirements.
對動態庫的支持提供了擴展lua的關鍵手段。它容許嵌入lua的程序擴展或減小腳本中可使用的功能。
Applications embedding Lua initiate the process to load libraries.  Libraries registered by the embedding application can be linked statically or dynamically. This allows applications to link only the subset of libraries it needs. Usually, the application initiates the extension library by calling an initialization function that registers global tables, variables and/or functions in the Lua’s script environment.
嵌入lua的應用程序初始化裝載庫的過程。由應用程序註冊的庫能夠被動態或者靜態連接上。這容許應用程序按需連接庫的子集。通常來講,應用程序經過調用一個註冊全局表、變量或函數的初始化函數來初始化擴展庫。
Dynamic libraries can also be loaded directly from the Lua environment. This is done by calling the loadlib function with the filename of the dynamic library and the name of its initialization function. The use of this function allows the user to locate the library and call its initialization function.
動態庫也能夠直接從lua環境中直接加載。這經過調用loadlib函數,傳入動態庫的文件名與其初始化函數名稱來完成。
Lua’s library architecture also enables loading parts of a library. For instance, the standard Lua functions include separate calls to initialize the coroutine library, the auxiliary library, string matching library, library loader, etc. This allows application greater control over what functions are available to script it embeds.
lua的庫架構也容許僅加載部分庫。例如,標準的lua函數會各自獨立地初始化協程庫、輔助庫、字符串匹配庫、庫加載器等等。這容許應用程序從很大程度上控制哪些函數是其嵌入的腳本可用的。
As an example, consider an application that wants to allow its script to access every part of the standard Lua libraries except the dynamic library loader. The application should call the every library initialization in the Lua standard library except luaopen_loadlib.
舉個例子,若是一個應用用程序須要容許其腳本訪問標準的任何部分,除開動態庫加載器,那麼它應該調用除luaopen_loadlib之外全部lua標準庫的初始化函數。

Coroutines

協程

Lua supports asymmetric coroutines [19]. The virtual machine kernel is responsible for maintaining state associated with the virtual machine subsystem. State managed by the virtual machine kernel consists of one or more execution states, each of which can fully specify the state of the processor.  This design allows coroutines to be implemented by creating new execution states each time a new coroutine is loaded and the active execution state is changed when a coroutine yields.
lua支持非對稱協成。虛擬機內核負責維持虛擬機子系統的相關狀態。狀態由虛擬機內核管理,包括1個或多個執行態,每個執行態徹底指定處理器的狀態。這種設計容許在新協程加載或活動執行態改變時(當其餘協程讓出時)經過建立新執行態來實現協程。

Conclusion

結束語

Lua has archived its goal of simplicity, extensibility, portability, reliability, and performance.
Lua已經將達到其簡明性、擴展性、輕便性、可靠性與性能方面的目標(YoungMan注:archived…不管如何也不多是歸檔的意思,應該是achieve,達到,難道單詞寫錯了?)。
Most goals derive from the fact that the language is simple. Simplicity was achived by allowing the user to create language features through the use of meta-mechanisms instead of implementing features directly in the language. Meta-mechanisms allow users to implement inheritance, namespace, and debugging. Other features such as type checking are not included in Lua.
Lua的大部分設計目標能實現是由於Lua自己十分簡單。Lua容許用戶經過使用元表或者元方法來建立語言特性而不是直接在語言中實現這些特性,這樣便有了其簡明性。元表或者元方法容許用戶實現繼承、名字空間,以及debug。lua並不包含其餘諸如類型檢查之類的特性。
Extensibility was accomplished by a comprehensive interface between Lua and C/C++. The API allows Lua to call functions in C, create objects in C++, and call methods in C++ objects. Furthermore, C/C++ applications can easily call Lua functions and access data in variables, tables, and metamethods. The success of extending the Lua library is demonstrated by the number of libraries that extend Lua’s functionalities [13,14,15,16].
擴展性經過在Lua與C/C++之間的綜合性接口完成。這些API容許lua在C中調用函數,在C++中建立對象,並在C++對象中調用方法。 更棒的是,C/C++應用程序能夠輕鬆地調用lua函數,並訪問存儲在變量、table中的數據與元方法。數學庫對lua的功能性擴展說明了擴展lua庫 的成功之處。
Reliability was achieved by extensively using tests to certify language stability. As described in History of Lua [3], 「to keep a language is much more than to design it. Complete attention to detail is essential in all aspects.」 In addition, reliability was achieved by using an established reference model of a compiler.
可靠性則是經過普遍的測試來證實其穩定性來作到的。如Lua發展史(文檔)中所述,」比起設計一門語言,更重要的是保持好它。不論就哪方面來講,對細節的全面關注都是必須的。」。此外,可靠性還經過使用編譯器的建立引用模型實現。
The Lua architecture places a significant emphasis on performance.  Performance tactics include using a virtual machine that can receive precompiled opcodes and implementing the lexer and parser by hand.  The virtual machine allows applications to completely bypass the normal parse sequence when the Lua scripts have been precompiled.  Implementing the lexer and parser by hand improves performance when a script is loaded by providing more efficient components than automated tools could provide.
Lua的架構很是強調高性能。高性能策略包括使用虛擬機來接收預編譯操做碼以及手工實現詞法、語法分析器。虛擬機使得在腳本預編譯後,應用程序能徹底繞開詞法分析的過程。與自動化工具相比,手工實現的詞法、語法分析器組件性能高效得多,這樣在腳本加載時性能有很大改善。

Appendix A: VM Code Generation Examples

附錄 A:虛擬機代碼生成示例

The virtual machine supports 51 operations, although most programs use a small subset of these operations.  Lua VM operations can be generated in a human readable form by running the external bytecode generator (called luac) with the 「-p」 and 「-l」 options.
虛擬機支持51種操做,儘管大部分程序僅使用這些操做的一個微小子集。Lua虛擬機操做經過使用」-p」和」-l」選項運行外部字節碼生成器生成,生成結果是可讀的。
First, consider the simple Lua script below:
首先,考慮下面這個簡單的lua腳本:

y = 5

print(y)

Running this script through luac with the 「-p」 and 「-l」 generates the following bytecodes:
以」-p」和」-l」選項在luac(YoungMan注:即lua compiler。編譯lua源碼會獲得兩個exe,這是其中之一。)中執行腳本會生成如下字節碼:

LOADK           0 1     ; 5

SETGLOBAL       0 0     ; y

GETGLOBAL       0 2     ; print

GETGLOBAL       1 0     ; y

CALL            0 2 1

RETURN          0 1 0

The LOADK operation loads a value from the constants table and places it in a register.  Its first argument is the stack register to store the result in and its second argument is an index into the global constants table. The GETGLOBAL operation reads a value from the globals table. Its result is stored in the register specified by the first argument. The second argument is a reference to a constant table entry that has a pointer to a global value.  The SETGLOBAL operation sets a value in the globals table.  Its first argument is a register that has the value to be saved in the globals table.  The second argument is an index into the constant table that has a pointer to a value in the globals table.  The CALL operation calls a function.  Its first argument gives the register that has a pointer to the function.  The function arguments are placed sequentially in registers after the function pointer. Its second argument contains the number of function arguments plus one. Its third argument contains the number of values that the function returns.  The return values are placed sequentially in the registers starting at the register specified for the first argument. Finally, RETURN is called when a function is finished.  The first argument is the stack position of the returned first value; the other returned values are in the following positions. The second argument of the RETURN statement is the number of returned values plus one.
LOADK操做從常量表中加載變量並放入到寄存器中。它的第一個參數是要存放結果的棧寄存器,第二個參數則是全局常量表中的索引位置。 GETGLOBAL操做從全局表中讀取值。其結果存放在第一個參數指定的寄存器中。該操做的第二個參數是指向常量表入口(entry)的引用,常量表中有 指向全局值的指針。SETGLOBAL操做將值存入全局表中,第一個參數是一個寄存器,其中存放須要被存放到全局表的值,第二個是常量表中索引位置,常量 表中有指向全局表中值的指針。CALL操做調用函數。第一個參數指定了存放函數指針的寄存器。函數參數則按序放置於函數指針以後的寄存器中。第二個參數則 是函數參數個數加1。第三個參數是函數須要返回的值的個數(YoungMan注:此處應該是錯誤,從後面來看,應當是個數再加1)。返回值按序放置於第一 個參數指定的及其以後的寄存器中。最後,函數完成時RETURN被調用。第一個參數是第一個返回值在棧中的位置;其餘返回值則緊隨以後。RETURN表達 式的第二個參數則是返回值個數加1.
In the example, the first two operations are responsible for setting y to 5.  The first operation loads constant #1 and places it in register #0.  The second operation takes register #0 and places it in a list of globally accessible values indexed by constant #0.  From these opcodes, we can determine that constant 0 contains the global value index to y and constant 1 contains the number 5.
在這個例子中,先兩步操做負責將y賦值爲5。第一步加載常量#1並放入寄存器#0,第二步將#0寄存器的值放入全局表中,索引位置由常量#0指 定(YoungMan注:#0是指命令中的」0″,參看上面的字節碼命令的圖示)。經過這些操做碼,咱們能夠肯定常量#0中存放對全局值Y的索引,而常 量#1中存放數值5。
The next four operations of the example are used to call the print function.  The first GETGLOBAL operation retrieves the print function from the global table and places it in register #0.  The second operation places y in register #1.  Finally, we execute the CALL operation. The CALL operation expects the called function and all of its arguments to be in sequential registers. Because the print function is stored in register #0 then the first argument must be stored in register #1. The third argument of the CALL function is the number of expected return values plus one.
示例中接下來的四步操做用來調用print函數。第一個GETGLOBAL操做從全局表中獲取print函數,並放入寄存器#0。第二個 GETGLOBAL則將y放入寄存器#1。最後,執行CALL操做。CALL調用函數及放置於一列寄存器中的參數。因爲print函數存放在#0寄存器 中,因此第一個參數只能存放在#1中。CALL的第三個參數是返回值個數加1。
Now, let’s consider a more complex example:
如今在看個更復雜的例子:

local x = 10

function test()

x = 2

end

luac generates the following bytecodes for this example:
luac爲示例生成以下字節碼:

main:

LOADK           0 0     ; 10

CLOSURE         1 0     ; 0xa051940

MOVE            0 0 0

SETGLOBAL       1 1     ; test

RETURN          0 1 0

test:

LOADK           0 0     ; 2

SETUPVAL        0 0 0   ; x

RETURN          0 1 0

This example uses three opcodes that the previous example did not: CLOSURE, SETUPVAL, and MOVE. The objective of the CLOSURE instruction is to create an instance of a function.  Its first argument specifies the base register that the instantiated function references. The base is used to store a reference to the instantiated function. If the instantiated function has upvalues, one register for each upvalue will be reserved sequentially created after the base register. The CLOSURE operation’s second argument is the index into the table of function prototypes of the function we want to access.
這個例子中使用了前一例中沒有用到的三個操做碼:CLOSURE,SETUPVAL以及MOVE。CLOSURE指令的目的是建立函數實例。其 第一個參數指定實例化函數存放的基準寄存器。若是函數有非局部的變量,各個非局部變量將按序建立於基準寄存器以後的寄存器中。CLOSURE操做的第二個 參數是函數原型表中的索引,該索引處的函數正是咱們想要訪問的(YoungMan注:應該各個函數也是存放在一個函數列表中)。
The SETUPVAL instruction sets the value of a variable in the outer scope. Its first argument is the register that has the data source. The second argument is the destination’s index in the upvalues list.
SETUPVAL指令設置非局部的變量。第一個參數是存放原始數據的寄存器。第二個參數是該變量在非局部變量列表中目標存放位置的索引值。
The MOVE instruction copies data from a specific register to another. The first argument is the destination register and the second argument is the source. The third argument is ignored.
MOVE指令負責將數據從一個寄存器中拷貝到另外一個寄存器中。第一個參數是目標寄存器,第二個則是源寄存器。第三個參數忽略。
In the provided example, the first operation of the main chunk sets the x variable to 10 by loading constant #0 into register #0. The second operation places a reference to the function testfunc in register #1. The third operation has no affect because the first and second arguments of the move operation refer to the same register. Next, the fourth operation stores a reference to the function  test in the global table so it can be called outside the current scope. Finally, the last instruction in the main chunk is a return instruction which effectively ends the chunk.
在所舉示例中,main代碼塊的第一步操做經過把常量#0加載到#0寄存器實現對x變量賦值爲10。第二步操做將函數test的引用放置到寄存 器#1中。第三步操做無效,由於MOVE操做的先後兩個參數指向同一寄存器。接下來,第四部操做在全局表中存放test函數的引用,這樣出了當前做用域其 同樣能夠被調用。最後,main代碼塊的末尾指令是RETURN操做,高效地結束當前塊。
The second part is the code of the test function. The first operation in test loads 2 into register #0 by copying the value stored in the local constant’s table.  Next, the test function sets  x to 2 by setting the upvalue #0 to the value in register #0. Finally, the test function returns control to the previous caller.
第二步則是test函數的代碼。第一步是加載2到寄存器#0中,這依靠拷貝局部常量表中的數據完成。而後,test函數經過設置非局部變量#0爲寄存器#0中的值,爲x賦值2,最後test函數將控制權返回給調用者。

Acknowledgements

致謝

We would like to thank all the authors of Lua, in particular Roberto Ierusalimschy who suggested the description of some features, provided reference material for the construction of this document, and gave us figures for closures and tables.
咱們但願感謝lua的全部做者,特別是Roberto Ierusalimschy,他描述了部分特性,提供了構建這份文檔的參考材料,並給出了閉包與表的圖示。

In addition, we would like to thank Ralph Johnson for assisting on organizational aspects of this document, as well as, the main content definition.

此外,咱們但願感謝 Ralph Johnson在組織這份文檔的各個方面以及肯定文檔的主要內容上給出的幫助。

Moreover, Rici Lake’s email about the hash table implementation has supplied some of the content of the Table section.

再有,Rici Lake關於hash表實現的電子郵件也提供了table一節的部份內容。


References

參考

[1]              R. Ierusalimschy, L. H. de Figueiredo, W. Celes, 「Lua-An Extensible Extension Language」, Software: Practice & Experience 26  pp 635-652 #6 (1996).

[2]              L. H. de Figueiredo, R. Ierusalimschy, W. Celes, 「The Design and Implementation of a Language for extending applications」, Proceedings of XXI Brazilian Seminar on Software and Hardware, pp 273-283 (1994).

[3]              R. Ierusalimschy, L. H. de Figueiredo, W. Celes, 「The Evolution of an Extension Language: A History Of Lua」, Proceedings of V Brazilian Symposium on Programming Languages B-14–B-28 (2001).

[4]              L. H. de Figueiredo, R. Ierusalimschy, W. Celes, Lua: An Extensible Embedded Language a Few Metamechanisms Replace a Host of Features」, Dr. Dobb’s Journal 21 #12 pp 26-33. [DDJ] (Dec 1996)

[5]              J. Gracia-Martin, M. Sutil-Martin, 「The Extreme Compiling Pattern Language」

[6]              Associative Array at Wikipedia, 「http://en.wikipedia.org/wiki/Associative_array

[7]              R. Ierusalimschy, L. H. de Figueiredo, W. Celes, 「Lua 5.0 Reference Manual」, Technical Report MCC-14/03, PUC-Rio, 2003

[8]              L. H. de Figueiredo, R. Ierusalimschy, W. Celes, The Design And Implementation Of A Language For Extending Applications」, Proceedings of XXI Brazilian Seminar on Software and Hardware pp 273-283 (1994).

[9]              Len Bass, Paul Clements, and Rick Kazman; 「Software Architecture in Practice」, second edition, Apr 9, 2003, Addison-Wesley

[10]              Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, and Michael Stahl; 「Pattern-Oriented Software Architecture: A System of Patterns」 1996, Wiley & Sons

[11]              Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides; 「Design Patterns」 1994, Addison-Wesley

[12]              「The Kepler Project」 at http://www.keplerproject.org, 2004, Fábrica Digital and PUC-Rio

[13]              「tolua」 at http://www.tecgraf.puc-rio.br/~celes/tolua/ , 2004, Tecgraf/PUC-Rio

[14]              「IUP」 http://www.tecgraf.org/iup, 2004, Tecgraf/PUC-Rio

[15]              「LuaSocket」 at http://www.tecgraf.org/luasocket, 2004, Fábrica Digital and PUC-Rio

[16]              「Luaorb」 at http://www.tecgraf.puc-rio.br/luaorb , 2004, Tecgraf/PUC-Rio

[17]              John R. Levine, Tony Mason, Doug Brown; 「Lex & Yacc」 1992, O’Reilly & Associates

[18]              David Jeske, 「A Fast Multiple-Inheritance Tag Method Implementation in Lua」, at http://www.lua.org/notes/ltn008.html Lua Technical Note 8.

[19]              Ana Lúcia de Moura, Noemi Rodriguez, and Roberto Ierusalimschy; 「Coroutines in Lua」 July 2004 Journal of Universal Computer Science, pp 910-925 10(7).

[20]              Kein-Hong Man. 「A No-Frills Introduction to Lua 5 VM Instructions」, November 28th, 2004

[21]     Richard P. Brent; Reducing the retrieval time of scatter storage techniques

2

相關文章
相關標籤/搜索