天天看點

nim 語言實作INI解析

在 http://code.taobao.org/p/parseIni/src/ 有代碼,可以用svn下載下傳

因為INI文法比較簡單

[section1]

key1= xxx

key2 = xxx

key3 =xxx

...

[section2]

key21=xxx

key22=xxx

...

...

解析這個的目的:

1 練習一下nim語言。很久的代碼了,從0.12的時候,現在已經0.15了。聲援一下Nim,盼着快出1.0

2 練習一下編譯原理

包含詞法分析,文法分析(特别的簡單)。

最後聲稱一個 section的table(和 c++中的map類似)

這個table 又包含一個table 這個table ,是 key-value 的一個 table

代碼:

#
#
#            ParseIni
#        (c) Copyright 2015 bkdrong
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## scan.nim 實作詞法分析
## 
import
    windows,tables,os
proc printf(formatstr: cstring) {.importc: "printf", varargs,
header: "<stdio.h>".}
type 
    TOKEN_KIND = enum
        TK_NONE,    #如果是TK_NONE,則出錯了
        TK_ID,      #辨別符
        TK_EQU,     #等号
        TK_STR,     #字元串
        TK_INT,     #整數類型
        TK_SECTION  #區域

    SCAN_STATE = enum
        SS_START,
        SS_INID,
        SS_INSTR,
        SS_ININT,
        SS_INSECTION,
        SS_END
    TTOKEN = object
        kind:TOKEN_KIND
        value:string
    TSymbolList = Table[string,string]
    TSection = Table[string,TSymbolList]

const 
    END_CHAR = '\0'        
#全局變量區
var 
    g_buffer : string  = """
    [bkdrong]
        name  = "ronggf"
        scope = 90
        age   = 41
        num   = 20
        nation = "china"
    [xieglt]
        name  = "xielt"
        scope = 80
        age   = 37
        num   = 16
        nation = "japen"    
    """
    g_buffer_pos : int = 0
    g_curr_token : TTOKEN
    g_section_lst:TSection = initTable[string,TSymbolList]()
#獲得下一個字元
proc getCharFormBuffer():char = 
    if g_buffer_pos < g_buffer.len :        
        result = g_buffer[g_buffer_pos]
    else: 
        result = '\0'
    g_buffer_pos+=1

proc backBuffer() =
    g_buffer_pos-=1   
#get a token from g_buffer
proc getTok():TTOKEN = 
    var 
        state = SS_START
        token_value :string =""
        ret_val:TTOKEN
    while true:        
        var c = getCharFormBuffer()
        #printf("get char 0x%x\n",c)
        case state :
        of SS_START:
            if c in {'a'..'z','A'..'Z'} :
                state = SS_INID
                token_value =token_value & c
            elif c =='"':
                state = SS_INSTR                
            elif c=='=':
                state = SS_END
                ret_val.kind = TK_EQU
                ret_val.value="="
            elif c in {'0'..'9'}:
                state = SS_ININT
                token_value = token_value & c
            elif c == '[':
                state = SS_INSECTION
            elif c == END_CHAR:
                state = SS_END
                ret_val.kind = TK_NONE
        of SS_INID:
            if c notin {'a'..'z','A'..'Z','0'..'9','_'}:
                backBuffer()
                ret_val.kind =TK_ID
                ret_val.value = token_value
                state = SS_END
            else:
                token_value = token_value & c
        of SS_ININT:
            if c notin {'0'..'9'} :
                backBuffer()
                ret_val.kind =TK_INT
                ret_val.value = token_value
                state = SS_END
            else:
                token_value = token_value & c
        of SS_INSTR:
            if c!='"':
                token_value = token_value &c
            else :
                ret_val.kind = TK_STR
                ret_val.value = token_value
                state = SS_END
        of SS_INSECTION:
            if c!=']':
                token_value = token_value &c
            else :
                ret_val.kind = TK_SECTION
                ret_val.value = token_value
                state = SS_END
        else:discard
        if state == SS_END:
            return ret_val
proc match(kind:TOKEN_KIND) =
    if g_curr_token.kind == kind :
        g_curr_token = getTok()
    else :
        echo "expected :",kind," but got ",g_curr_token.kind
        quit(1)
proc test_gettoken() =
    while true:
        var tok :TTOKEN
        tok = getTok()
        if tok.kind == TK_NONE:
            break
        else :
            echo tok
proc assignStmt(symlst:var TSymbolList):bool =
        if g_curr_token.kind == TK_ID :
            var 
                sym_name:string
                sym_value:string
            sym_name = g_curr_token.value
            match(TK_ID)
            match(TK_EQU)            

            if g_curr_token.kind == TK_STR:
                sym_value = g_curr_token.value
                match(TK_STR)                
            elif g_curr_token.kind == TK_INT:
                sym_value = g_curr_token.value
                match(TK_INT)
            else:
                sym_value ="no value"
            symlst.add(sym_name,sym_value)
            result = true
        elif g_curr_token.kind == TK_NONE or g_curr_token.kind == TK_SECTION:
            result = false
        else:
            echo "assignListStmt failed"
            quit(1)

proc assignListStmt(symlst: var TSymbolList) =
    while true :
        if not assignStmt(symlst) :
            break
proc stmt() =      
    g_curr_token = getTok()
    while true:
        if g_curr_token.kind == TK_SECTION:
            var section_name = g_curr_token.value
            match(TK_SECTION)
            var sym_list : TSymbolList = initTable[string,string]()
            assignListStmt(sym_list)
            #echo "section_name ",section_name
            g_section_lst.add(section_name,sym_list)
            #echo "item:",g_section_lst[section_name]
            #echo "sym_list",sym_list
        elif g_curr_token.kind==TK_NONE :
            break
        else:
            echo "tk is = ",g_curr_token
            quit(1)
proc readINI(filename:string,section_name:string,key_name:string):string =
    result=""
    var 
        file = open(filename)
        content : string = ""
    if file!=nil :
        for str in lines(file) :
            content &= str & "\n"
        g_buffer = content
        stmt()
        try:
            let symlst = g_section_lst[section_name]
            result = symlst[key_name]
        except:
            echo "except:",repr(getCurrentExceptionMsg())
            #echo "can not find the key_name:",key_name," in section_name:",section_name
    else:
        echo "open file:",filename," failed"
proc main() =
    echo "CPU:",hostCPU," OS:",hostOS
    if paramCount() < 1:
        echo ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"
        echo "scan inifile"
        echo "example:scan\x0a\x09 c:\\test\\haha.ini"
        echo ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"
        return

    let filename = commandLineParams()[0]
    if not existsFile(filename):
        echo "file " & filename & " not exist"
        return
    stdout.write("input a section string:")
    let section_name = readline(stdin)
    stdout.write("input a key string:")
    let key_name = readline(stdin)
    echo "result = " , readINI(filename,section_name,key_name)
main()
#test_gettoken()            
#stmt()
#echo repr(g_symbol_lst)
#echo g_section_lst



           

繼續閱讀