Analyseur / Lexer ignorant les règles de grammaire incomplètes
Question
J'ai un analyseur syntaxique et un lexer écrits dans ocamlyacc et ocamllex. Si le fichier à analyser se termine prématurément, comme dans le cas où j'oublie un point-virgule à la fin d'une ligne, l'application ne génère pas d'erreur de syntaxe. Je me rends compte que c’est parce que je soulève et attrape EOF et que cela fait que le lexer ignore la règle inachevée, mais comment dois-je le faire pour générer une erreur de syntaxe?
Voici mon analyseur actuel (simplifié),
%{
let parse_error s = Printf.ksprinf failwith "ERROR: %s" s
%}
%token COLON
%token SEPARATOR
%token SEMICOLON
%token <string> FLOAT
%token <string> INT
%token <string> LABEL
%type <Conf.config> command
%start command
%%
command:
| label SEPARATOR data SEMICOLON { Conf.Pair ($1,$3) }
| label SEPARATOR data_list { Conf.List ($1,$3) }
| label SEMICOLON { Conf.Single ($1) }
label :
| LABEL { Conf.Label $1 }
data :
| label { $1 }
| INT { Conf.Integer $1 }
| FLOAT { Conf.Float $1 }
data_list :
| star_data COMMA star_data data_list_ending
{ $1 :: $3 :: $4 }
data_list_ending:
| COMMA star_data data_list_ending { $2 :: $3 }
| SEMICOLON { [] }
et lexxer (simplifié),
{
open ConfParser
exception Eof
}
rule token = parse
| ['\t' ' ' '\n' '\010' '\013' '\012']
{ token lexbuf }
| ['0'-'9']+ ['.'] ['0'-'9']* ('e' ['-' '+']? ['0'-'9']+)? as n
{ FLOAT n }
| ['0'-'9']+ as n { INT n }
| '#' { comment lexbuf }
| ';' { SEMICOLON }
| ['=' ':'] { SEPARATOR }
| ',' { COMMA }
| ['_' 'a'-'z' 'A'-'Z']([' ']?['a'-'z' 'A'-'Z' '0'-'9' '_' '-' '.'])* as w
{ LABEL w }
| eof { raise Eof }
and comment = parse
| ['#' '\n'] { token lexbuf }
| _ { comment lexbuf }
exemple de fichier d'entrée,
one = two, three, one-hundred;
single label;
list : command, missing, a, semicolon
Une solution consiste à ajouter un appel récursif dans la règle de commande à elle-même à la fin et à ajouter une règle vide, qui construisent toutes une liste pour revenir au programme principal. Je pense que j'interprète peut-être Eof comme une attente et une condition de fin, plutôt qu'une erreur dans le lexer, est-ce correct?
La solution
ocamlyacc
ne consomme pas nécessairement toute l'entrée. Si vous voulez le forcer à échouer si la totalité de l'entrée n'est pas analysable, vous devez faire correspondre EOF
dans votre grammaire. Au lieu de générer Eof
dans votre lexer, ajoutez un jeton EOF
et remplacez le symbole start
par
%type <Conf.config list> main
main:
EOF { [] }
| command main { $1::$2 }