|
PlicTalk Implementation
[ Home ]
[ PlicTalk Grammar ]
Data Structures
- Node Size = 12 bytes
- Node List Size = 256 nodes/page x 12 B/node = 3072 B/page
- Page List Size = 512 page slots x 11 B/slot = 5632 bytes
- Bottom level Node List (or Page) has 256 Nodes
- Page List or Chapter has 512 slots, each slot points to a Page
- Slot = 4-byte ptr. + 2 x 24-bit ptrs. + updated byte
- 4-byte ptr. points to node list (page) = null when page is swapped out
- 2 x 24-bit ptrs. point to next/prev. pages in linked list
- Chapter List Size = 2048 page lists x 4 B/page list = 8192 bytes
- Address Space = 32 (4-byte ptr.) + 4 (16 bytes/node) = 36 bits = 64 GB
- Page Addr: 4-bit book no + 11-bit chapter no + 9-bit page idx = 24 bits
- Addr Value: 24-bit page addr + 8-bit node idx = 32 bits
- Node Types:
- Object Ref Node: 0 bit, 31-bit refcount, 0 bit, 31-bit root (attr) ptr., code ptr.
- Object Value Node: 0 bit, 31-bit refcount, 1 bit, header, 4-byte value
- Lisp Node: 1 bit, 31-bit refcount, 2 x 4-byte ptrs. to lisp, obj ref, obj val nodes
- Tree Node: 2 x 16-bit hdrs., 2 x 4-byte values
- Stack Node: 4-byte hdr., 4-byte value, 4-byte next
- Base Node: prior base ptr., root (parm/loc) ptr., next ptr.
- Long Node: 64-bit long, double, or bitarray
- Callback Node: obj ref, code ptr.
- String Node: 3 x 4-byte Unicode chars.
- ByteZero Node: 12 bytes, null-terminated
- Bytes Node: 12 bytes
- Array Node: same as stack node, used for string, bytezero, bytes, bitarray values
- String List: bytezero value, may contain newline chars.
- Dict Leaf Node: string list, array node (list of values)
- Header Values:
- node, boolean, int, long, float, double, object, lisp, string, bytezero, bytes, bitarray, array, dict, dict leaf, callback, op, paren, null
- Binary Tree: has root, max path size = 32 bits
- object node
- base node
- array, dict
- Class Inheritance:
- Code ptr. may point to method in ancestor class
- Current class includes all ancestor attributes
- Page Types:
- Book (up to 16 of these), Chapter, Page
- Also called chapter list, page list, node list, respectively
- Swap File:
- 16 chapter lists (2048 ptrs. x 4 B/ptr.) = 128K
- 16 x 2048 page lists (512 page slots x 11 B/slot) < 192 MB
- 16 x 2048 x 512 node lists x 3072 B/page = 48 GB
- Tree-balancing functionality needed
- Little or no support for arrays
- Linked list implemented in library using Seq class:
- Data structure: lisp nodes, each node points to current, rest of list
- Properties: first/last lisp nodes, count
- Methods: pop, push, append, insert, delete, getnode, getnext, getprior
- StackSeq class: top, count, pop, push
- Reference counting used for garbage collection
- PageUpdate(currIdx)
- // move pageList[curridx] to end of occupied page list
- if prev(currIdx) = 0 then firstFull = next(currIdx)
- else next(prev(currIdx)) = next(currIdx)
- if next(currIdx) = 0 then lastFull = prev(currIdx)
- else prev(next(currIdx)) = prev(currIdx)
- // append currIdx to occupied page list
- next(currIdx) = prev(currIdx) = 0
- if lastFull = 0 then firstFull = currIdx
- else
- next(lastFull) = currIdx
- prev(currIdx) = lastFull
- lastFull = currIdx
- updated(curridx) = 1
- return
- PageSwapNew(newIdx)
- Occurs when adding a new node list, forcing an old node list to be swapped out
- // newIdx = addr. of new page
- // free page list in RAM is empty
- oldIdx = firstFull // head of occupied page list
- if updated(oldIdx) then write old node list to swap file
- newIdx = addr. of new page
- currIdx = oldIdx
- PageAppend(curridx, newIdx)
- updated(currIdx) = 1
- return
- NullPointer(currIdx)
- Occurs when null ptr. (swapped page) encountered in page list
- // currIdx = idx of swapped page in page list
- // pageList[currIdx] is null
- if next(currIdx) = 0 and firstEmpty = currIdx then PageSwap(curridx)
- else PageRefresh(curridx)
- return
- PageRefresh(curridx)
- Read node list (of currIdx) from swap file
- newIdx = addr. of page just read
- PageAppend(curridx, newIdx)
- return
- PageSwap(curridx)
- // free page list in RAM is empty
- oldIdx = firstFull // head of occupied page list
- if updated(oldIdx) then write old node list to swap file
- Read node list (of currIdx) from swap file
- Overwrite old node list with data read (addr = oldIdx)
- PageAppend(curridx, oldIdx)
- return
- PageAppend(currIdx, newIdx)
- pageList[currIdx] = newIdx
- // remove currIdx from empty page list
- if prev(currIdx) = 0 then firstEmpty = next(currIdx)
- else next(prev(currIdx)) = next(currIdx)
- if next(currIdx) = 0 then lastEmpty = prev(currIdx)
- else prev(next(currIdx)) = prev(currIdx)
- // append currIdx to occupied page list
- next(currIdx) = prev(currIdx) = 0
- if lastFull = 0 then firstFull = currIdx
- else
- next(lastFull) = currIdx
- prev(currIdx) = lastFull
- lastFull = currIdx
- updated(currIdx) = 0
Code Execution
All PlicTalk source code is in Polish notation, in which operators precede their operands. The following algorithm is used, in which operators are stored in one stack and operands in a separate stack. Executable code consists of tree nodes.
rightp = root
while true do
if rightp = 0 then
op = pop operator
if op = root then
return true
if op = while/for/loopbody then
pop rightp from operator stack
continue
if op = if then
pop rightp from operator stack
pop (
continue
if op = block then
pop (
pop if from operator stack
pop (
pop rightp from operator stack
continue
count = 0
while true do
pop operand
if open parenthesis then break
push operand on operator stack
increment count
if op = call then
rightp = handlecall(count)
continue
if op = constructor then
rightp = handlecons(count)
continue
if op = callback then
rightp = handlecallback(count)
continue
pop operand from operator stack
push operand
repeat count - 1 times
pop operand from operator stack
push operand
rightpop = pop
leftpop = pop
push op(leftpop, rightpop)
// (: obj attridx) => obj...
if count = 1 then
if unary op then
push op(pop)
else
rightpop = pop
leftpop = pop
push op(leftpop, rightpop)
rightp = pop operator
continue
currnode = getnode(rightp)
if open parenthesis then
push on operand stack
push rightp on operator stack
rightp = currnode.downp
else if operand then
push on operand stack
rightp = currnode.rightp
else if operator then
push on operator stack
rightp = currnode.rightp
else if funcbody then
handlebody
rightp = currnode.rightp
else if endfunc then
pop downto begin from operator stack
pop rightp from operator stack
else if while/for then
rightp = currnode.rightp
push rightp, while/for on operator stack
else if do then
flag = pop
if not flag then
pop while, rightp from operator stack
pop rightp from operator stack
pop (
else if continue then
pop downto while from operator stack
pop rightp from operator stack
else if break then
pop downto while from operator stack
pop rightp, rightp from operator stack
pop (
else if breakfor then
pop downto for from operator stack
pop rightp, rightp from operator stack
pop (
pop (
else if contfor then
pop downto loopbody from operator stack
pop rightp from operator stack
else if then then
flag = pop
if flag then
rightp = currnode.rightp
else
pop if from operator stack
pop (
pop rightp from operator stack
else
return false
pop downto x from operator stack:
pop multiple from operator stack
if: pop (
while: pop (
do block while flag:
while true do block if not flag then break
handlecons(count):
pop classref from operator stack
gen objref: root 0/1 = instance/class vars
push objref on operator stack
return handlecall(count)
handlecall(count):
pop objref from operator stack
push objref
pop codept from operator stack
return handlecodept(codept, count)
handlecodept(codept, count):
repeat count - 2 times
pop val from operator stack
push val
push count - 1
return codept
handlecallback(count):
pop callback from operator stack
unpack objref, codept
push objref
return handlecodept(codept, count)
handlebody:
count = pop
root = new node
for i = count - 2 downto 0 do
parm = pop
add parm to 1st half of tree[i]
objref = parm
rightp = currnode.rightp
loccount = currnode value
repeat loccount times
add null node to 2nd half of tree
rightp = currnode.rightp
[ Back to Top ]
|
|
|