Простейший из парсеров в go tool yacc

С помощью этой команды:

go tool yacc -p Verb -o verb.go boilerplate.y

попытка построить этот файл yacc:

// boilerplate.y
%{

package main

import (
    "bufio"
    "fmt"
    "os"
    "unicode"
)

%}

%% 

.|n   ECHO;

%%

func main() {
    fi := bufio.NewReader(os.NewFile(0, "stdin"))
  s, err := fi.ReadString('n')
  if err != nil {
    fmt.Println('error', err)
  } 

  VerbParse(&VerbLex{s: s})
}

ошибка: bad syntax on first rule: boilerplate.y:16

успешно получил этот пример для работы:

https://github.com/golang-samples/yacc/blob/master/simple/calc.y

пытаясь построить свой собственный и работать через книгу lex & yacc. Ресурсы, как представляется, ограничены отсутствием.

1 ответов


у вас неправильный rule в вашей спецификации.

файл спецификации имеет следующий вид:

declarations
%%
rules
%%
programs

где rule определено как:

A  :  BODY  ;

здесь A - это нетерминальный символ, а тело состоит из токенов (терминальных символов), не-терминалов и литералов. The : и ; являются обязательными компонентами синтаксиса объявления правил.

отсюда правило:

.|\n   ECHO;

синтаксически неверен.

поскольку вы просто пытаетесь повторить ввод, очень простая реализация на основе calc.y будет следующим (файл Эхо.y):

правила

%%

in : /* empty */
  | in input '\n'
     { fmt.Printf("Read character: %s\n", ) }
  ;

input : CHARACTER
  | input CHARACTER
      { $$ =  +  }
  ;

программа

%%

type InputLex struct {
    // contains one complete input string (with the trailing \n)
    s string
    // used to keep track of parser position along the above imput string
    pos int
}

func (l *InputLex) Lex(lval *InputSymType) int {
    var c rune = ' '

    // skip through all the spaces, both at the ends and in between
    for c == ' ' {
        if l.pos == len(l.s) {
            return 0
        }
        c = rune(l.s[l.pos])
        l.pos += 1
    }

    // only look for input characters that are either digits or lower case
    // to do more specific parsing, you'll define more tokens and have a 
    // more complex parsing logic here, choosing which token to return
    // based on parsed input
    if unicode.IsDigit(c) || unicode.IsLower(c) {
        lval.val = string(c)
        return CHARACTER
    }

    // do not return any token in case of unrecognized grammer
    // this results in syntax error
    return int(c)
}

func (l *InputLex) Error(s string) {
    fmt.Printf("syntax error: %s\n", s)
}

func main() {
    // same as in calc.y
}

func readline(fi *bufio.Reader) (string, bool) {
    // same as in calc.y
}

чтобы скомпилировать и запустить эту программу, выполните в командной строке следующее:

go tool yacc -o echo.go -p Input echo.y
go run echo.go

как вы можете видеть, вам придется определить свой собственные правила разбора в Lex метод. Структура InputLex предназначен для хранения значений во время анализа входных данных. InputSymType автоматически генерируется и определяется %union объявлен в declaration часть спецификация.

насколько я могу судить, нет способа напрямую использовать JISON или regex для сопоставления с помощью go's . Возможно, вам придется заглянуть в другие библиотеки.

более подробную информацию можно найти здесь: http://dinosaur.compilertools.net/yacc/

полный рабочий код здесь:https://play.golang.org/p/u1QxwRKLCl