Простейший из парсеров в 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