Code Monkey home page Code Monkey logo

luago-book's Introduction

luago-book's People

Contributors

aviland avatar guzhoudiaoke avatar shakem avatar zxh0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luago-book's Issues

7.2 LuaTable 第123页代码中的put函数内delete(self._map,key)是否是多余的?

	if idx, ok := key.(int64); ok && idx >= 1 {
		arrLen := int64(len(self.arr))
		if idx <= arrLen {
			self.arr[idx-1] = val
			if idx == arrLen && val == nil {
				self._shrinkArray()
			}
			return
		}
		if idx == arrLen+1 {
			delete(self._map, key) //此处的delete
			if val != nil {
				self.arr = append(self.arr, val)
				self._expandArray()
			}
			return
		}
	}

一直没想明白这里delete(self._map, key)的用途是什么。感觉不管什么情况下,都不会真正触发delete。

当插入Table的键是“len(数组)+1”后,那么数组会自动重整(expand),map键“len(数组)+1”的值应该一直是空,后续操作应该不会触发delete。

例如:

  1. Table状态为:数组 [1,2,3,4] 字典 {6:6,8:8}
  2. 设置t[5]=5后,此时不会真正触发delete,会自动expand成状态:数组[1,2,3,4,5,6] 字典{8:8}
  3. 此时,字典len(数组)+1键为空,之后的操作也不会真正触发delete

只有当状态为:数组[1,2,3,4],字典{5:100,6:6,8,8}时。
此时,插入t[5]=5,才会真正触发delete。但我实在想不到,在什么情况下,会出现上述情况,即在字典中存在键“len(数组)+1”。

望解答,谢谢。

9.3.2节的 getTabUp最后不应该vm.Pop(1)

vm.PushGlobalTable() +1
vm.GetRK(c) +1
vm.GetTable(-2) +0
vm.Repace(a) -1
vm.Pop(1) -1

如果执行了vm.Pop(1)会把加载进栈的Go函数清除,相当于调用getTabUp后没有起到任何作用

16.4 表达式文法产生式EBNF有误

原文法:

exp   ::= exp12
exp12 ::= exp11 {or exp11}
exp11 ::= exp10 {and exp10}
exp10 ::= exp9 {(‘<’ | ‘>’ | ‘<=’ | ‘>=’ | ‘~=’ | ‘==’) exp9}
exp9  ::= exp8 {‘|’ exp8}
exp8  ::= exp7 {‘~’ exp7}
exp7  ::= exp6 {‘&’ exp6}
exp6  ::= exp5 {(‘<<’ | ‘>>’) exp5}
exp5  ::= exp4 {‘..’ exp4}
exp4  ::= exp3 {(‘+’ | ‘-’) exp3}
exp3  ::= exp2 {(‘*’ | ‘/’ | ‘//’ | ‘%’) exp2}
exp2  ::= {(‘not’ | ‘#’ | ‘-’ | ‘~’)} exp1
exp1  ::= exp0 {‘^’ exp2}
exp0  ::= nil | false | true | Numeral | LiteralString
		| ‘...’ | functiondef | prefixexp | tableconstructor

这里的文法 + - * / or and 这些是没有处理左结合的,..没有处理右结合
虽然实现的代码上处理了
符合编译原理的文法应该是这样的

exp ::= exp12
exp12 ::= (exp12 or exp 11) | exp11
exp11 ::= (exp11 and exp10) | exp10
......
省略
......
exp5 ::= exp4 {'..' exp5}

消除左递归形式:
@表示空产生式(ε)

exp12 ::= exp11 exp12'
exp12' ::= (or exp11 exp12') | @
exp11 ::= exp10 exp11'
exp11' ::= (and exp10 exp11') | @
......
省略
......
exp5 ::= exp4 {'..' exp5}

由于exp12'与exp11'这些尾项产生式都是尾递归
因此可以使用书中的循环进行优化

func parseExp12(lexer *Lexer) Exp {
	exp := parseExp11(lexer)
	for lexer.LookAhead() == TOKEN_OP_OR {
		line, op, _ := lexer.NextToken()
		lor := &BinopExp{line, op, exp, parseExp11(lexer)}
		exp = optimizeLogicalOr(lor)
	}
	return exp
}

exp5相当于原地展开递归

func parseExp5(lexer *Lexer) Exp {
	exp := parseExp4(lexer)
	if lexer.LookAhead() != TOKEN_OP_CONCAT {
		return exp
	}

	line := 0
	exps := []Exp{exp}
	for lexer.LookAhead() == TOKEN_OP_CONCAT {
		line, _, _ = lexer.NextToken()
		exps = append(exps, parseExp4(lexer))
	}
	return &ConcatExp{line, exps}
}

书的EBNF有误导成分

Page111 for 循环指令示例有误

在讨论FORPREPFORLOOP指令时,书上举了下面的例子:

$ luac -l -l -
for i=1,2,100 do f() end
^D
main <stdin:0,0> (8 instructions at 0x7f9980c031f0)
0+ params, 5 slots, 1 upvalue, 4 locals, 4 constants, 0 functions
	1	[1]	LOADK    	0 -1	; 1
	2	[1]	LOADK    	1 -2	; 2
	3	[1]	LOADK    	2 -3	; 100
	4	[1]	FORPREP  	0 2	; to 7
	5	[1]	GETTABUP 	4 0 -4	; _ENV "f"
	6	[1]	CALL     	4 1 1
	7	[1]	FORLOOP  	0 -3	; to 5
	8	[1]	RETURN   	0 1
constants (4) for 0x7f9980c031f0:
	1	1
	2	2
	3	100
	4	"f"
locals (4) for 0x7f9980c031f0:
	0	(for index)	4	8
	1	(for limit)	4	8
	2	(for step)	4	8
	3	i	5	7
upvalues (1) for 0x7f9980c031f0:
	0	_ENV	1	0

但是在P112,画堆栈的时候画的却是:

i:
(step): 2
(limit): 100
(index): 1)

但是如果按照示例中for循环写法,step应该是100,而不是2。考虑到后面的讲解,我猜测应该是示例写错了,应该是:

for i=1,100,2 do f() end

Page152 CLOSURE 指令模式有误

P152 处书上是这样讲解CLOSURE指令的:

CLOSURE 指令(iBx 模式)...

但是并不存在iBx模式,而应该是“iABx模式”

lua的垃圾回收机制

有幸拜读了作者的《自己动手实现Lua》一书,收益良多. 要是能把lua的垃圾回收机制也讲解下.那就更好了

Page96中 LOADNIL 指令三个操作数的作用

书上这样讲 LOADNIL指令的三个操作数的作用:

寄存器的起始索引由操作数 A 指定,寄存器数量则由操作数 B 指定,操作数 C 并没有用。

但是在书上举的例子中:

$ luac -l -
local a,b,c,d,e
^D
main <stdin:0,0> (2 instructions at 0x7fca03500070)
0+ params, 5 slots, 1 upvalue, 5 locals, 0 constants, 0 functions
	1	[1]	LOADNIL  	0 4
	2	[1]	RETURN   	0 1

里面 B 操作数的值为4,但是其实是给5个值(a,b,c,d,e)赋值nil
所以我觉得"寄存器的数量由操作数 B 指定"这句话稍微有点歧义。

LuaStack的Set函数忽略了idx等于top的情况

存在如下Lua字节码:

main hello.lua:0,0 (69 instructions at 005f8670)
0+ params, 14 slots, 1 upvalue, 8 locals, 9 constants, 3 functions
1 [10] CLOSURE 0 0 ; 005f8880
2 [13] CLOSURE 1 1 ; 005f8a98
3 [12] SETTABUP 0 -1 1 ; _ENV "fail"
4 [17] CLOSURE 1 2 ; 005f8af0
5 [19] MOVE 2 0
..................................................................................................................
..................................................................................................................
..................................................................................................................

原来的Set函数忽略了idx == top的情况
对于上面的CLOSURE与MOVE指令运行都会失败

以下是C++版本的修复方法

void Set(int idx, const LuaValue& value)
{
	int absIdx = AbsIndex(idx);

	if(absIdx == top + 1)
		++top;

	if(absIdx > 0 && absIdx <= top)
	{
		slots[absIdx - 1] = value;
	}
	else
	{
		panic("invalid index!");
	}
}

Page109, TEST 指令的讲解

P109,关于TEST指令,书上是这样讲的:

判断寄存器 A(索引由操作数 A 指定)中的值转换为布尔值之后是否和操作数 C 表示的布尔值一致,如果一致,则跳过下一条指令。

但是根据TEST指令的伪码:

if not (R(A) <=> C) then pc++

可以发现其实应该是“如果不一致,则跳过下一条指令”。

改错和其他

感谢作者写了这本书!以下是我在阅读的时候遇到的一些错误:

页数 章节 位置 原文 更正
124 7.2 倒数一段话第一行 由于set()方法…… 由于put(...)方法……
178 9.3.2 倒数第一段话最后一行 录下创建inst_Upvalue.go文件 录下创建inst_upvalue.go文件
187 10.1.2 第一段话第一行 我们再用“luc -l -l”分析…… 我们再用“luac -l -l”分析……
192 10.2.2 倒数第二段话倒数第三行 读者打开luaStack.go文件…… 读者打开lua_stack.go文件……
227 12.2.1 第一段话第一行 请读者打开luaTable.go文件…… 请读者打开lua_table.go文件……
228 12.2.2 倒数第一段话第二行 (和luaTable.go文件…… (和lua_table.go文件……
372 19.3 倒数第一段话第二行 就可以通过面相对象…… 就可以通过面向对象……
373 19.3 第二句代码的打印结果 print(s:len()) --> 2 print(s:len()) --> 3

另外,Windows和Mac的命令行略有不同,而这本书上是Mac版命令行,我开了一个库记录本书Windows版命令行内容,不关心命令行差异的用Windows的读者可以从这库里直接拷贝命令行内容。

请教一下第10章 关于upvalue的问题

您好,首先十分感谢作者,这本书对帮助我理解虚拟机底层运行机制帮助很大。目前看到第10章,也参考了这个仓库自己实现了一个Rust版本。
在实现好第10章的内容后对upvalue的一些情况做了测试,但是发现有一种情况不能通过,debug后觉得可能是对于upvalue的引用问题。
用例代码如下:

local step = 1
local start = 0
local function assert(v)
    if not v then
        fail()
    end
end
function newCounter()
    local count = start
    return function()
        count = count + step
        return count
    end
end

c1 = newCounter()
assert(c1() == 1)
assert(c1() == 2)

c2 = newCounter()
assert(c2() == 1)   -- 3
assert(c1() == 3)   -- 4
assert(c2() == 2)  -- 5

似乎是因为newCounter获取到startcount之后,后续对count的更改都会同时反馈在最外层的start上。
我想请教一下,lua对于这种情况闭包获取到的upvalue的生命周期是不是还有其他的处理呢?如果有的话是如何实现的呢,在官方c实现的版本里应该去了解哪部分的代码?

如果您方便的话请您帮忙解答一下,非常感谢!

编译器版本:
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
操作系统:
macOS 11.3.1
附编译后的指令:

main <tests/upvalue.lua:0,0> (52 instructions at 0x7f8d3a406590)
0+ params, 5 slots, 1 upvalue, 3 locals, 7 constants, 2 functions
        1       [1]     LOADK           0 -1    ; 1
        2       [2]     LOADK           1 -2    ; 0
        3       [7]     CLOSURE         2 0     ; 0x7f8d3a406700
        4       [14]    CLOSURE         3 1     ; 0x7f8d3a406b40
        5       [8]     SETTABUP        0 -3 3  ; _ENV "newCounter"
        6       [16]    GETTABUP        3 0 -3  ; _ENV "newCounter"
        7       [16]    CALL            3 1 2
        8       [16]    SETTABUP        0 -4 3  ; _ENV "c1"
        9       [17]    MOVE            3 2
        10      [17]    GETTABUP        4 0 -4  ; _ENV "c1"
        11      [17]    CALL            4 1 2
        12      [17]    EQ              1 4 -1  ; - 1
        13      [17]    JMP             0 1     ; to 15
        14      [17]    LOADBOOL        4 0 1
        15      [17]    LOADBOOL        4 1 0
        16      [17]    CALL            3 2 1
        17      [18]    MOVE            3 2
        18      [18]    GETTABUP        4 0 -4  ; _ENV "c1"
        19      [18]    CALL            4 1 2
        20      [18]    EQ              1 4 -5  ; - 2
        21      [18]    JMP             0 1     ; to 23
        22      [18]    LOADBOOL        4 0 1
        23      [18]    LOADBOOL        4 1 0
        24      [18]    CALL            3 2 1
        25      [20]    GETTABUP        3 0 -3  ; _ENV "newCounter"
        26      [20]    CALL            3 1 2
        27      [20]    SETTABUP        0 -6 3  ; _ENV "c2"
        28      [21]    MOVE            3 2
        29      [21]    GETTABUP        4 0 -6  ; _ENV "c2"
        30      [21]    CALL            4 1 2
        31      [21]    EQ              1 4 -1  ; - 1
        32      [21]    JMP             0 1     ; to 34
        33      [21]    LOADBOOL        4 0 1
        34      [21]    LOADBOOL        4 1 0
        35      [21]    CALL            3 2 1
        36      [22]    MOVE            3 2
        37      [22]    GETTABUP        4 0 -4  ; _ENV "c1"
        38      [22]    CALL            4 1 2
        39      [22]    EQ              1 4 -7  ; - 3
        40      [22]    JMP             0 1     ; to 42
        41      [22]    LOADBOOL        4 0 1
        42      [22]    LOADBOOL        4 1 0
        43      [22]    CALL            3 2 1
        44      [23]    MOVE            3 2
        45      [23]    GETTABUP        4 0 -6  ; _ENV "c2"
        46      [23]    CALL            4 1 2
        47      [23]    EQ              1 4 -5  ; - 2
        48      [23]    JMP             0 1     ; to 50
        49      [23]    LOADBOOL        4 0 1
        50      [23]    LOADBOOL        4 1 0
        51      [23]    CALL            3 2 1
        52      [23]    RETURN          0 1
constants (7) for 0x7f8d3a406590:
        1       1
        2       0
        3       "newCounter"
        4       "c1"
        5       2
        6       "c2"
        7       3
locals (3) for 0x7f8d3a406590:
        0       step    2       53
        1       start   3       53
        2       assert  4       53
upvalues (1) for 0x7f8d3a406590:
        0       _ENV    1       0

function <tests/upvalue.lua:3,7> (5 instructions at 0x7f8d3a406700)
1 param, 2 slots, 1 upvalue, 1 local, 1 constant, 0 functions
        1       [4]     TEST            0 1
        2       [4]     JMP             0 2     ; to 5
        3       [5]     GETTABUP        1 0 -1  ; _ENV "fail"
        4       [5]     CALL            1 1 1
        5       [7]     RETURN          0 1
constants (1) for 0x7f8d3a406700:
        1       "fail"
locals (1) for 0x7f8d3a406700:
        0       v       1       6
upvalues (1) for 0x7f8d3a406700:
        0       _ENV    0       0

function <tests/upvalue.lua:8,14> (4 instructions at 0x7f8d3a406b40)
0 params, 2 slots, 2 upvalues, 1 local, 0 constants, 1 function
        1       [9]     GETUPVAL        0 0     ; start
        2       [13]    CLOSURE         1 0     ; 0x7f8d3a406c40
        3       [13]    RETURN          1 2
        4       [14]    RETURN          0 1
constants (0) for 0x7f8d3a406b40:
locals (1) for 0x7f8d3a406b40:
        0       count   2       5
upvalues (2) for 0x7f8d3a406b40:
        0       start   1       1
        1       step    1       0

function <tests/upvalue.lua:10,13> (7 instructions at 0x7f8d3a406c40)
0 params, 2 slots, 2 upvalues, 0 locals, 0 constants, 0 functions
        1       [11]    GETUPVAL        0 0     ; count
        2       [11]    GETUPVAL        1 1     ; step
        3       [11]    ADD             0 0 1
        4       [11]    SETUPVAL        0 0     ; count
        5       [12]    GETUPVAL        0 0     ; count
        6       [12]    RETURN          0 2
        7       [13]    RETURN          0 1
constants (0) for 0x7f8d3a406c40:
locals (0) for 0x7f8d3a406c40:
upvalues (2) for 0x7f8d3a406c40:
        0       count   1       0
        1       step    0       1

Page 263, 14.3.8 标识符和关键字

func (self *Lexer) NextToken() (line, kind int, token string) {
      // skip long segment code
    if c == '_' || isLetter(c) {
        // ...
        return line, kind, token  // 这里应该是self.line, go初始化始终line为0
       // ...
       return line, TOKEN_IDENTIFIER, token  // 这里应该是self.line, go初始化始终line为0
    }
}

源码ch14是对的,书上是错的

感谢信

发一个不算 issue 的 issue:
有幸在一个前辈的推荐下拜读了您的这本书,目前正在阅读,感觉不管从行文还是代码的安排上都非常舒适,极大地帮助我提高了对编译原理和高级语言虚拟机的兴趣和相关知识。
谨以此文表达对您的感谢😄

Page127 GetTable方法的讲解

P127处,GetTable方法中用到了getTable方法:

为了减少重复,我们把根据键从表里取值的逻辑抽取成GetTable()方法,代码如下所示。

但是下面展示的却是getTable()方法的代码,而且根据上下文可知,应该是”抽取成getTable()方法。“

同理,P129中介绍SetTable方法时也出现了类似的错误。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.