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?

Était-ce utile?

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 }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top