Golang으로 해석기를 만들어 봤어요.

12308 단어 Go
갑작스럽지만 며칠 전 열린 학생 대상 경연대회에서 골랑제 해석기(Copal)에 참가했다.
이날 발표에서 드디어 Gopher군이 웃었습니다. Gopher군에게 감사드립니다.
나는 질문에 대답할 때 다양한 말을 들을 각오를 다졌지만, 나무랄 데 없는 질문에서 w를 구했다.
잠시 후에 트위터를 볼게요. "Golang의 포장"아닌가요?일각에서는
네, 맞아요.
개발 기간은 그거였고, 현재는 골랑과 차별화된 기능을 탑재하지 못하도록 최선을 다했다.
그리고 테스트 코드 기준과 1줄도 못 적어서 솔직히 미안해요.
(이미 생각해 봤지만 질문에 대답할 때 질문을 받지 못해서 다행이다...)
그럼, 오프닝은 여기까지, 골랑이 반년 +α제가 대학 시험 기간의 여가 시간을 이용해서 2, 3주 정도 만든 해석기를 소개해 드리겠습니다.
예전에 골랑제 해석기(여러 배 길이의 계산 기능을 가진 계산기에 근접)를 살짝 제작한 적이 있는데, 이번에는 다른 지침으로 제작하기로 했다.
안의 구조가 상당히 다르기 때문에 거의 다 다시 한 거예요...(지난번에는reflect, 이번에는interface로 실시)
그리고 제가 Qita에서 투고한 것은 이번이 두 번째이니 사정을 봐주세요.

코팔의 특징에 대해 자신의 생각대로 조목조목 열거하다

  • 외관과 주요 동작을 그대로 유지한다.
    차이점은 금형의 유연성(자동형 전환)에 관한 것이다.

  • 사용할 수 없습니다. 기본 형식은 방법이 있습니다.
  • string ---- has_prefix, has_suffix, split, trim_left, draw, reg_draw
  • slice ----- join, filter, unfilter
  • 클립보드 I/O 함수가 있어 좀...
     str := clip_read(), clip_write("Copal")
  • 형의 반환값의 수량은 가변 길이이다.같은 함수라도 매개변수 값이 다릅니다.
    뒤에 나오는 7LED의 예입니다.스플릿 등을 볼 수 있다면...

  • Gopher군의 인기를 모방해 마스코트 Copher군(나의 Qita 아이콘의 호박색 버전)을 제안했다.
    연하장 십이지신을 준비하기 위해 직접 그린 것으로 자유롭게 사용할 수 있다.

  • 지금부터 간단하게 설명해 드리자면 골랑과 코팔의 코드가 별로 차이가 없어 보이니 주의하세요.

    자구 해석


    나는 혼자서 모두 600줄 정도를 썼지만 그래도 마음대로 썼다.
    하지만 다음 동영상을 찾으면
    Lexical Scanning in Go - Rob Pike
    https://www.youtube.com/watch?v=HxaD_trXwRE
    나는 이것이 Golang에 설치되어 있다고 생각한다.

    문법 분석


    그럼요. 저는 Goyacc를 썼어요.
    아래 사이트 등을 참고했지만 나름대로 써낸 부분도 있어 별로 예쁘지 않은 코드로 변했다.
    Qiita
  • goyacc 사용
    http://qiita.com/draftcode/items/c9f2422fca14133c7f6a
  • GOyacc를 통한 문법 해석
    http://qiita.com/k0kubun/items/1b641dfd186fe46feb65
  • 고야cc에 대한 알기 쉬운 해설을 실었다.
    Github
  • mattn/anko
    https://github.com/mattn/anko
  • 유창하게 정리되어 있어 비교적 유창하게 읽힌다.
    항상 mattn씨의 코드를 통해 배웁니다.
    IBM
    *IBM Knowledge Center-lex 및 yacc의 프로그램 정보
    http://www-01.ibm.com/support/knowledgecenter/?lang=ja#!/ssw_aix_53/com.ibm.aix.genprogc/doc/genprogc/lex_yacc_prg_info.htm%23d722d3e759mela
    나는 모르는 부분을 뛰어넘어 대충 한 번 읽었다.

    변수 유형의 실현에 관하여


    코팔에서 변수의 유형을 인트, 플랫, 부울, 스트링, 펀치, 슬리케이션, 찬, 닐 8가지로 나눈다.
    int.go
    type Int int
    
    func (v Int) Add(x Val) Val {
        v += x.Int()
        return &v
    }
    
    Val는 상기 8가지 유형의interface이다.
    예시에서 사칙연산, 비트연산, 논리연산, 유형전환 등에 대해 모든 유형에 대해 장황하게 기술하였다.(약 수천 줄 정도)
    혼자 정의된 파일을 사용하여 원본 코드를 자동으로 생성하는 것이 비교적 쉽습니다... orz

    프로세스 실행 정보


    지난번에 제작된 여러 배의 계산 기능을 가진 함수 계산기 풍해석기는 문법 트리를 제거하면서 실행하는 형식으로 이번에는 조금 다른 방식을 시도했다.
    그건 문법 트리를 제거하고 집중해서 실행하는 게 빠르겠지... 이런 간단한 생각의 토대 위에서.(특별한 기준은 없다...)
    VM을 혼자 준비하는 기술이 없어서 어떻게 하면 좋을지 고민하다가 무명함수를 자꾸 쓰는 등 잘 모르는 것을 생각해서 그걸로 실행했다.
    대개 좋은 방법은 아닌 것 같고 변수에서 값을 얻을 때는 다음과 같은 분위기의 코드입니다.
    func (s *Semanticer) parseExpr(expr ast.Expr) *vm.FuncBlock {
        fs := vm.NewFuncBlock()
        switch expr := expr.(type) {
        case *ast.IdentExpr:
            varStack := s.GetVarStack(expr.Lit)
            fs.Funcs.Append(func() {
                s.Push(varStack.Get())
            })
        //  ...
        }
        //  ...
        return fs
    }
    
    무명 함수func(){}에서 varStack.Get() 변수 창고에서 값을 얻은 다음 s.Push()로 이 값을 다른 구역으로 밀어 값을 교환합니다.
    매개 변수와 반환 값이 없는 무명 함수를 사용하기 때문에 약간 빙빙 돌았다.
    변수 창고varStack의 정의는 map[string]*val.Stack로 각 변수 이름의 창고를 사용하여 역할 영역을 관리한다.
    다른 곳을 설명하면 좋지 않은 부분이 조금씩 드러나기 때문에 이렇게...

    Copal의 샘플 코드

  • 계수기(배타 제어 포함)
  • counter.cop
    func counter() {
        ch := new_chan(0)
        go func() {
            i := 1
            for {
                ch <- i
                i++
            }
        }()
        return ch
    }
    
    func loop(no, chan, n, waitChan) {
        println("start", no)
        for i := 0; i < n; i++ {
            <-chan
        }
        println("end", no)
        waitChan <- 0
    }
    
    n := 250000
    ch, waitCh := counter(), new_chan(0)
    //  4並列アクセス
    go loop(1, ch, n, waitCh)
    go loop(2, ch, n, waitCh)
    go loop(3, ch, n, waitCh)
    go loop(4, ch, n, waitCh)
    //  待機
    <-waitCh; <-waitCh
    <-waitCh; <-waitCh
    
    println("require", n * 4 + 1)
    println("result ", <-ch)
    
    exit(0)
    
    start 1
    start 2
    start 3
    start 4
    end 1
    end 4
    end 3
    end 2
    require 1000001
    result  1000001
    
    방문 카운터 아래 횟수.
    4 병렬× 25000회 +1(확인)=1000001
    의 값입니다.
  • 7 LED 같은
  • 7led.cop
    buf := 10
    chA, chB, chC, chD := new_chan(buf, buf, buf, buf)
    
    //  A, B, C, D
    chA0, chA1, chA2, chA3, chA4, chA5 := cir_split(6, chA)
    chA00, chA01 := cir_split(2, cir_not(chA0))
    chB0, chB1, chB2, chB3, chB4, chB5 := cir_split(6, chB)
    chB00, chB01, chB02, chB03, chB04, chB05 := cir_split(6, cir_not(chB0))
    chC0, chC1, chC2, chC3, chC4, chC5, chC6, chC7 := cir_split(8, chC)
    chC00, chC01, chC02, chC03, chC04 := cir_split(5, cir_not(chC0))
    chD0, chD1, chD2, chD3, chD4 := cir_split(5, chD)
    chD00, chD01, chD02, chD03, chD04, chD05, chD06, chD07 := cir_split(8, cir_not(chD0))
    
    //  a, b, c, d, e, f, g
    cha := cir_or(chA1, cir_and(chB1, chD1), chC1, cir_and(chB00, chD00))
    chb := cir_or(chB01, cir_and(chC2, chD2), cir_and(chC00, chD01))
    chc := cir_or(chA2, chB2, chC01, chD3)
    chd := cir_or(chA3, cir_and(chB02, chD02), cir_and(chC3, chD03), cir_and(chA00, chB03, chC4), cir_and(chB3, chC02, chD4))
    che := cir_or(cir_and(chB04, chD04), cir_and(chC5, chD05))
    chf := cir_or(chA4, chB4, cir_and(chC03, chD06))
    chg := cir_or(chA5, cir_and(chB5, chC04), cir_and(chC6, chD07), cir_and(chA01, chB05, chC7))
    
    func send(a, b, c, d) {
        chA <- a;   chB <- b
        chC <- c;   chD <- d
    }
    
    //  2進数
    //  9
    send(1, 0, 0, 1)
    //  8
    send(1, 0, 0, 0)
    //  7
    send(0, 1, 1, 1)
    //  6
    send(0, 1, 1, 0)
    //  5
    send(0, 1, 0, 1)
    //  4
    send(0, 1, 0, 0)
    //  3
    send(0, 0, 1, 1)
    //  2
    send(0, 0, 1, 0)
    //  1
    send(0, 0, 0, 1)
    //  0
    send(0, 0, 0, 0)
    
    close(chA, chB, chC, chD)
    
    led7(cha, chb, chc, chd, che, chf, chg)
    
    출력된 숫자는 아래와 같이 파란색으로 표시됩니다.

    7단 LED의 회로를 시뮬레이션할 수 있습니다.
    모든 논리문에 골프장을 생성하고 나란히 이동한다.
    조금씩 실제 회로에 가까워지죠?!
    트리거 회로가 있을 수도 있고.
  • 문법 고라법
  • syntax_highlighter.cop
    for i, line := range fread($[0]) {
        println(i + 1, ":", line.reg_draw("white", "[a-zA-Z_$0-9]+").reg_draw("cyan", "func|fread|fwrite|close|clip_read|clip_write|sleep|has_prefix|trim_left|print|println|filter|unfilter|len|exit|exec|reg_draw").reg_draw("magenta", "for|return|else|if|go|range").reg_draw("blue", "[!.,=;<>+]|[:=]|\\-").reg_draw("yellow", "\"([^\\\"]|\\\\.)*\"").reg_draw("dark_gray", "(^[  ]*//.*|//[^\"]*$)"))
    }
    
    출력 결과는 이런 느낌입니다.

    첫 번째 매개 변수 파일을 불러오고 줄 수와 컬러로 표시합니다.
    정칙적인 표현은 당시의 리듬에 따라 썼기 때문에 상당히 잘못된 것 같아서...
  • 메아리 서버
  • echo_server.cop
    println(server("8080", func(req) (string) {
        return req
    }))
    
    소켓 통신이 가능한지 확인할 때 간혹 사용한다.

    전망하다


    아래와 같은 구상이 있었지만 실제 진력하는 목표는 아직 확립되지 않았다...

  • 그림 문자와 전각 문자 코드 지원
    지금의 스타일은 반각문자 이외의 여분의 문자를 모두 튀어나오고 그 부분만 바뀔 뿐...

  • shell
    예를 들어'`로 둘러싸면 셸 실행은 채널을 통해 할 수 있었으면 좋겠다고 생각합니다.
  • stdinChan, stdoutChan, stderrChan = `ls`
    stdinChan <- "."
    for i, v := range stdoutChan {
        //  ファイル名一覧をどうにかする処理    
    }
    
    그리고 셸 파이프에 해당하는 부분을 통로로 간결하게 표현할 수 있다면 재미있을 것 같아요.
    (이제는 exec ("ls") 를 통해 실행이 끝날 때까지 기다리는 기능만 실현되었습니다.)
  • 추가 라이브러리
  • 나는 동적 링크로 추가 기능을 사용할 수 있었으면 좋겠다고 생각한다.
    Mac이면, copal.dylib 자동 읽기
    문자열을 매개 변수로 등록된 함수에 전달하고interface {] 함수를 되돌려주려고 하면 그에 상응하는 확장이 가능할 것 같습니다. (아직 하지 않았습니다.)
    func DylibLoad(str string) interfece{} {
        //  お好きな処理を書く
    }
    
    위의 함수에서 맵을 사용하여 여러 함수를 등록한 다음 문자열로 이 함수의 이미지를 호출합니다.
    이렇게 사용합니다.
    f := dyload("func-name")//  関数を動的にロード
    f("Hello Gopher!")//    fは文字列を取得してなんかいい感じの処理をしてくれるユーザー拡張関数
    

    최후


    Giithub에서 Golang이 만든 해석기에 대한 정보를 찾아봤는데 견습 Gopher로서 이해가 잘 안 돼서 위와 같은 독특한 이상한 설치가 됐어요.
    또한 언어 처리에 관한 지식은 대학 수업에서(ry
    어쩔 수 없어요. 저는 전공 서적을 독학했지만 기본적으로 잘 몰라요. 그래서 여기서 먼저 투고하고 싶어요. 피드백을 받을 수 있다면...
    Giithub은 이쪽에 있지만 기본적으로 개인 숙제라서 잘 안 써요.
    앞으로 저장된 원본 코드를 깨끗하게 하면서 업데이트하고 싶어요.
    https://github.com/nanoeru/copal
    --
    마지막으로 경연 발표회에서 골랑 고퍼 군을 홍보할 수 있어서 다행입니다.
    대학이라면 포치고퍼인데 이를 계기로 고퍼 파트너가 늘었으면 한다.
    만약 무슨 생각한 곳이 있다면 사양하지 말고 평론해 주십시오.
    그럼 지루한 졸문은 실례하겠습니다.

    좋은 웹페이지 즐겨찾기