python: เขียนโค๊ดคลี่แสต็กฟอนต์

เหตุมาจากต้องการดูการ instruct ของฟอนต์ DejaVu Sans
แต่โค๊ดอ่านยากเหลือเกิน เพราะเขียนข้อมูลเป็นสแต็กไว้ก่อน แล้วจึงเขียนโค๊ดตามหลัง ทำให้ดูยาก จึงเขียนสคริปต์แบบหยาบ ๆ มาคลี่ข้อมูลเรียงต่อท้ายคำสั่ง เพื่อให้ดูง่ายขึ้น ตั้งชื่อชั่วคราวว่า dfont.py
$ touch dfont.py; chmod 755 dfont.py; vi dfont.py
#!/usr/bin/env python

import sys

# ins_dict = { "COMMAND" : ("Description",pops,push), ... }
# pops,push: 0=NOOP, 1=1BYTE, 2=2BYTE, ...
#           -1=FIRST BYTE IS ONE BYTE COUNTER,
#           -2=FIRST BYTE IS TWO BYTE COUNTER, 
#           -3=CLEAR STACK
#           -4=REQUIRE SOME PROCESSING

ins_dict = {
    "AA" :       ("Adjust Angle", 1, 0),
    "ABS" :      ("ABSolute value", 1, 1),
    "ADD" :      ("ADD", 2, 1),
    "ALIGNPTS" : ("ALIGN Points", 2, 0),
    "ALIGNRP" :  ("ALIGN to Reference Point", 1, 0),
    "AND" :      ("logical AND", 2, 1),
    "CALL" :     ("CALL function", 1, 0),
    "CEILING" :  ("CEILING", 1, 1),
    "CINDEX" :   ("Copy the INDEXed element to the top of the stack", 1, -1),
    "CLEAR" :    ("CLEAR the stack", -3, 0),
    "DEBUG" :    ("DEBUG call", 1, 0),
    "DELTAC1" :  ("DELTA exception C1", -2, 0),
    "DELTAC2" :  ("DELTA exception C2", -2, 0),
    "DELTAC3" :  ("DELTA exception C3", -2, 0),
    "DELTAP1" :  ("DELTA exception P1", -2, 0),
    "DELTAP2" :  ("DELTA exception P2", -2, 0),
    "DELTAP3" :  ("DELTA exception P3", -2, 0),
    "DEPTH" :    ("DEPTH of the stack", 0, 1),
    "DIV" :      ("DIVide", 2, 1),
    "DUP" :      ("DUPlicate top stack element", 1, 1),
    "EIF" :      ("End IF", 0, 0),
    "ELSE" :     ("ELSE clause", 0, 0),
    "ENDF" :     ("END Function definition", 0, 0),
    "EQ" :       ("EQual", 2, 1),
    "EVEN" :     ("EVEN", 1, 1),
    "FDEF" :     ("Function DEFinition", 1, 0),
    "FLIPOFF" :  ("set the auto FLIP Boolean to OFF", 0, 0),
    "FLIPON" :   ("set the auto FLIP Boolean to ON", 0, 0),
    "FLIPPT" :   ("FLIP PoinT", 1, 0),
    "FLIPRGOFF" :    ("FLIP RanGe OFF", 2, 0),
    "FLIPRGON" : ("FLIP RanGe ON", 2, 0),
    "FLOOR" :    ("FLOOR", 2, 0),
    "GC" :       ("Get Coordinate projected onto the projection vector", 1, 1),
    "GETINFO" :  ("GET INFOrmation", 1, 1),
    "GFV" :      ("Get Freedom Vector", 0, 2),
    "GPV" :      ("Get Projection Vector", 0, 2),
    "GT" :       ("Greater Than", 2, 1),
    "GTEQ" :     ("Greater Than or EQual", 2, 1),
    "IDEF" :     ("Instruction DEFinition", 1, 0),
    "IF" :       ("IF test", 1, 0),
    "INSTCTRL" : ("INSTRuction execution ConTRoL", 2, 0),
    "IP" :       ("Interpolate Point", 1, 0),
    "ISECT" :    ("moves point p to the InterSECTion of two lines", 5, 0),
    "IUP" :      ("Interpolate Untouched Points through the outline", 0, 0),
    "JMPR" :     ("JuMP Relative", 1, 0),
    "JROF" :     ("Jump Relative On False", 1, 0),
    "JROT" :     ("Jump Relative On True", 3, 0),
    "LOOPCALL" : ("LOOP and CALL function", 2, 0),
    "LT" :       ("Less Than", 2, 1),
    "LTEQ" :     ("Less Than or Equal", 2, 1),
    "MAX" :      ("MAXimum of top two stack elements", 2, 1),
    "MD" :       ("Measure Distance", 2, 1),
    "MDAP" :     ("Move Direct Absolute Point", 1, 0),
    "MDRP" :     ("Move Direct Relative Point", 1, 0),
    "MIAP" :     ("Move Indirect Absolute Point", 2, 0),
    "MIN" :      ("MINimum of top two stack elements", 2, 1),
    "MINDEX" :   ("Move the INDEXed element to the top of the stack", 1, 3),
    "MIRP" :     ("Move Indirect Relative Point", 2, 0),
    "MPPEM" :    ("Measure Pixels Per EM", 0, 1),
    "MPS" :      ("Measure Point Size", 0, 1),
    "MSIRP" :    ("Move Stack Indirect Relative Point", 1, 0),
    "MUL" :      ("MULtiply", 2, 1),
    "NEG" :      ("NEGate", 1, 1),
    "NEQ" :      ("Not EQual", 2, 1),
    "NOT" :      ("logical NOT", 1, 1),
    "NPUSHB" :   ("PUSH N Bytes", -1, 0),
    "NPUSHW" :   ("PUSH N Words", -1, 0),
    "NROUND" :   ("No ROUNDing of value", 1, 1),
    "ODD" :      ("ODD", 1, 1),
    "OR" :       ("logical OR", 2, 1),
    "POP" :      ("POP top stack element", 1, 0),
    "PUSHB" :    ("PUSH Bytes", -4, 0),
    "PUSHW" :    ("PUSH Words", -4, 0),
    "RCVT" :     ("Read Control Value Table entry", 1, 1),
    "RDTG" :     ("Round Down To Grid", 0, 0),
    "ROFF" :     ("Round OFF", 0, 0),
    "ROLL" :     ("ROLL the top three stack elements", 3, 3),
    "ROUND" :    ("ROUND value", 1, 1),
    "RS" :       ("Read Store", 1, 1),
    "RTDG" :     ("Round To Double Grid", 0, 0),
    "RTG" :      ("Round To Grid", 0, 0),
    "RTHG" :     ("Round To Half Grid", 0, 0),
    "RUTG" :     ("Round Up To Grid", 0, 0),
    "S45ROUND" : ("Super ROUND 45 degrees", 1, 0),
    "SANGW" :    ("Set Angle Weight", 1, 0),
    "SCANCTRL" : ("SCAN conversion ConTRoL", 1, 0),
    "SCANTYPE" : ("SCANTYPE", 1, 0),
    "SCFS" : ("Sets Coordinate From the Stack using projection vector and freedom vector", 2, 0),
    "SCVTCI" :   ("Set Control Value Table Cut-In", 1, 0),
    "SDB" :      ("Set Delta Base in the graphics state", 1, 0),
    "SDPVTL" :   ("Set Dual Projection Vector To Line", 2, 0),
    "SDS" :      ("Set Delta Shift in the graphics state", 1, 0),
    "SFVFS" :    ("Set Freedom Vector From Stack", 2, 0),
    "SFVTCA" :   ("Set Freedom Vector To Coordinate Axis", 0, 0),
    "SFVTL" :    ("Set Freedom Vector To Line", 2, 0),
    "SFVTP" :    ("Set Freedom Vector To Projection Vector", 0, 0),
    "SHC" :      ("SHift Contour using reference point", 1, 0),
    "SHP" :      ("SHift Point using reference point", 1, 0),
    "SHPIX" :    ("SHift point by a PIXel amount", 2, 0),
    "SHZ" :      ("SHift Zone using reference point", 1, 0),
    "SLOOP" :    ("Set LOOP variable", 1, 0),
    "SMD" :      ("Set Minimum Distance", 1, 0),
    "SPVFS" :    ("Set Projection Vector From Stack", 2, 0),
    "SPVTCA" :   ("Set Projection Vector To Coordinate Axis", 0, 0),
    "SPVTL" :    ("Set Projection Vector To Line", 2, 0),
    "SROUND" :   ("Super ROUND", 1, 0),
    "SRP0" :     ("Set Reference Point 0", 1, 0),
    "SRP1" :     ("Set Reference Point 1", 1, 0),
    "SRP2" :     ("Set Reference Point 2", 1, 0),
    "SSW" :      ("Set Single Width", 1, 0),
    "SSWCI" :    ("Set Single Width Cut-In", 1, 0),
    "SUB" :      ("SUBtract", 2, 1),
    "SVTCA" :    ("Set freedom and projection Vectors To Coordinate Axis", 0, 0),
    "SWAP" :     ("SWAP the top two elements on the stack", 2, 2),
    "SZP0" :     ("Set Zone Pointer 0", 1, 0),
    "SZP1" :     ("Set Zone Pointer 1", 1, 0),
    "SZP2" :     ("Set Zone Pointer 2", 1, 0),
    "SZPS" :     ("Set Zone PointerS", 1, 0),
    "UTP" :      ("UnTouch Point", 1, 0),
    "WCVTF" :    ("Write Control Value Table in Funits", 1, 0),
    "WCVTP" :    ("Write Control Value Table in Pixel units", 2, 0),
    "WS" :       ("Write Store", 2, 0),
}

stack1_command = ("NPUSHB", "NPUSHW")
stack2_command = ("PUSHB", "PUSHW")

normal_command = []
for i in range(6):
    normal_command.append( [ j for j in ins_dict.keys() if ins_dict[j][1]==i ] )

#           -1=FIRST BYTE IS ONE BYTE COUNTER,
#           -2=FIRST BYTE IS TWO BYTE COUNTER, 
#           -3=CLEAR STACK
#           -4=REQUIRE PROCESS
pop_command = []
pop_command.append([])
for i in range(-1, -4, -1):
    pop_command.append( [ j for j in ins_dict.keys() if ins_dict[j][1]==i ] )


def line_format(cmd,stack,desc):
    #STRING, LIST, STRING
    return "%-24s %-10s ;%10s" % (cmd, "  ".join(stack), desc,)

def ins_decode(txt):
    txtlist = txt.split("\n")
    newlist = []
    commentlist = []
    stacklist = []
    sloop = 0
    i = 0
    while i < len(txtlist):
        if "[" in txtlist[i]:
            c1,c2 = txtlist[i].strip().split("[",1)
        else:
            c1,c2 = txtlist[i].strip(), ""
        #SKIP EMPTY LINE
        if c1 == "":
            i += 1
            continue
        #STACK: NPUSHB, NPUSHW
        if c1 in stack1_command:
            i += 1
            n = int(txtlist[i].strip())
            i += 1
            while n > 0:
                stacklist.append(txtlist[i].strip())
                i += 1
                n -= 1
            continue
        #STACK2: PUSHB, PUSHW
        if c1[:5] in stack2_command:

            n = int(txtlist[i].strip()[6:])
            i += 1
            while n > 0:
                stacklist.append(txtlist[i].strip())
                i += 1
                n -= 1
            continue
        temp_list = []
        #POP ONE
        if c1 in pop_command[1]:
            idx = stacklist.pop()
            temp_list = [idx]
            for j in range(int(idx)):
                temp_list.append(stacklist.pop())
            newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0]))
            i += 1
            continue
        #POP PAIR
        elif c1 in pop_command[2]:
            idx = stacklist.pop()
            temp_list = [idx]
            for j in range(int(idx)):
                temp_list.append(stacklist.pop())
                temp_list.append(stacklist.pop())
            newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0]))
            i += 1
            continue
        #POP ALL (CLEAR STACK)
        elif c1 in pop_command[3]:
            stacklist = []
            newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0]))
            i += 1
            continue

        #NORMAL COMMAND
        if c1 in normal_command[0]:
            count = 0
        elif c1 in normal_command[1]:
            count = 1
        elif c1 in normal_command[2]:
            count = 2
        elif c1 in normal_command[3]:
            count = 3
        elif c1 in normal_command[4]:
            count = 4
        elif c1 in normal_command[5]:
            count = 5
        else:
            count = -1
            print 'count-1:',c1
        if count > 0:
            if sloop > 0:
                count += sloop-1
                sloop = 0
        while count > 0:
            cnum = stacklist.pop()
            temp_list.append(cnum)
            if c1 == 'SLOOP':
                sloop = int(cnum)
            count -= 1
        newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0]))
        i += 1
    print '--------------------------------------'
    print '\n'.join(newlist)

if __name__ == "__main__":
    txt = sys.argv[1]
    ins_decode(txt)
เนื่องจากทำแบบหยาบ ๆ ใช้ลำบากหน่อย
เรียกใช้ด้วยคำสั่ง
$ ./dfont.py "
แปะด้วยโค๊ดที่คัดลอกมาจากฟอนต์ อักขระ n
"
ได้ผลเป็น
SRP0                     20         ;Set Reference Point 0
MIRP[rp0,min,rnd,grey]   70  11     ;Move Indirect Relative Point
MIRP[min,rnd,grey]       8  9       ;Move Indirect Relative Point
SHP[rp2]                 13         ;SHift Point using reference point
MIRP[rp0,rnd,grey]       78  0      ;Move Indirect Relative Point
MIRP[min,rnd,grey]       8  2       ;Move Indirect Relative Point
IUP[x]                              ;Interpolate Untouched Points through the outline
SVTCA[y-axis]                       ;Set freedom and projection Vectors To Coordinate Axis
MDAP[rnd]                1          ;Move Direct Absolute Point
ALIGNRP                  10         ;ALIGN to Reference Point
MIRP[rnd,grey]           188  12    ;Move Indirect Relative Point
MIRP[rp0,rnd,grey]       184  17    ;Move Indirect Relative Point
MDRP[rnd,grey]           14         ;Move Direct Relative Point
MIRP[min,rnd,grey]       135  6     ;Move Indirect Relative Point
SRP1                     1          ;Set Reference Point 1
SRP2                     14         ;Set Reference Point 2
SLOOP                    3          ;Set LOOP variable
IP                       0  9  3    ;Interpolate Point
IUP[y]                              ;Interpolate Untouched Points through the outline
SVTCA[x-axis]                       ;Set freedom and projection Vectors To Coordinate Axis
DELTAP1                  2  21  207  21  96 ;DELTA exception P1
ทดสอบอีกอันนึง เป็นอักขระ a
SRP0                     38         ;Set Reference Point 0
MIRP[rp0,min,rnd,grey]   69  20     ;Move Indirect Relative Point
MIRP[min,rnd,grey]       8  3       ;Move Indirect Relative Point
MDRP[min,rnd,grey]       31         ;Move Direct Relative Point
MDRP[rp0,rnd,grey]       11         ;Move Direct Relative Point
MIRP[min,rnd,grey]       8  9       ;Move Indirect Relative Point
SHP[rp2]                 13         ;SHift Point using reference point
SHP[rp2]                 24         ;SHift Point using reference point
SRP1                     3          ;Set Reference Point 1
IP                       23         ;Interpolate Point
IP                       0          ;Interpolate Point
IUP[x]                              ;Interpolate Untouched Points through the outline
SVTCA[y-axis]                       ;Set freedom and projection Vectors To Coordinate Axis
MDAP[rnd]                12         ;Move Direct Absolute Point
MDRP[rnd,grey]           23         ;Move Direct Relative Point
MIRP[rnd,grey]           140  17    ;Move Indirect Relative Point
MIRP[rp0,rnd,grey]       184  35    ;Move Indirect Relative Point
MIRP[rp0,min,rnd,grey]   185  28    ;Move Indirect Relative Point
MIRP[rp0,rnd,grey]       186  31    ;Move Indirect Relative Point
MIRP[min,rnd,grey]       134  32    ;Move Indirect Relative Point
SRP0                     17         ;Set Reference Point 0
MDRP[rnd,white]          14         ;Move Direct Relative Point
MIRP[min,rnd,white]      185  6     ;Move Indirect Relative Point
SRP0                     23         ;Set Reference Point 0
MIRP[min,rnd,white]      169  0     ;Move Indirect Relative Point
SRP1                     14         ;Set Reference Point 1
IP                       9          ;Interpolate Point
SRP1                     23         ;Set Reference Point 1
IP                       11         ;Interpolate Point
SRP2                     31         ;Set Reference Point 2
IP                       25         ;Interpolate Point
IUP[y]                              ;Interpolate Untouched Points through the outline
DELTAP1                  24  33  128  32  128  31  128  30  128  33  112  32  112  31  112  30  112  33  96  32  96  31  96  30  96  33  80  32  80  31  80  30  80  33  64  32  64  31  64  30  64  33  48  32  48  31  48  30  48 ;DELTA exception P1
SVTCA[x-axis]                       ;Set freedom and projection Vectors To Coordinate Axis
DELTAP1                  30  39  240  39  160  39  144  34  133  33  135  32  135  31  135  30  135  29  133  39  112  39  80  34  80  33  80  32  80  31  80  30  80  29  80  34  64  33  64  32  64  31  64  30  64  29  64  39  63  34  48  33  48  32  48  31  48  30  48  29  48 ;DELTA exception P1
Topic: