10 votes

Le plus simple des analyseurs syntaxiques dans l'outil go yacc

En utilisant cette commande :

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

Essai de construction de ce fichier 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})
}

Erreur : bad syntax on first rule: boilerplate.y:16

Cet exemple a fonctionné avec succès :

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

J'essaie de construire mon propre système et de travailler sur le livre lex & yacc. Les ressources semblent limitées, voire inexistantes.

8voto

abhink Points 4753

Vous avez une erreur rule dans votre cahier des charges.

Un fichier de spécification a la déclaration suivante :

declarations
%%
rules
%%
programs

Où un rule est définie comme suit :

A  :  BODY  ;

A est un symbole non terminal, tandis que CORPS se compose de tokens (symboles terminaux), de non-terminaux et de littéraux. Les : et ; sont des éléments obligatoires de la syntaxe de la déclaration de règle.

D'où la règle :

.|\n   ECHO;

est syntaxiquement incorrect.

Puisque vous essayez simplement d'afficher l'entrée, une implémentation très simple basée sur la fonction calc.y serait le suivant (fichier echo.y ) :

règles

%%

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

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

programme

%%

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
}

Pour compiler et exécuter ce programme, procédez comme suit à l'invite de commande :

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

Comme vous pouvez le constater, vous devrez définir vos propres règles d'analyse dans le fichier Lex méthode. La structure InputLex est conçu pour conserver les valeurs pendant que votre entrée est analysée. InputSymType est généré automatiquement et est défini par le %union déclarée dans le declaration partie du cahier des charges.

Pour autant que je sache, il n'y a pas de moyen d'utiliser directement JISON ou une expression rationnelle pour faire la correspondance en utilisant la fonction de go. yacc outil. Vous devrez peut-être jeter un coup d'œil à d'autres bibliothèques.

Plus de détails sont disponibles ici : http://dinosaur.compilertools.net/yacc/

Code complet ici : https://play.golang.org/p/u1QxwRKLCl

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X