Fehler bei Flex Handling (lex) und Bison (yacc)
-
07-07-2019 - |
Frage
Von dem Bison Handbuch:
In einem einfachen interaktiven Befehl Parser wobei jeder Eingang eine Leitung ist, kann es ausreichend sein, um zu ermöglichen, yyparse zu 1 zurück auf Fehler und haben die Anrufer der Rest der Eingangsleitung ignorieren, wenn das geschieht (und dann yyparse nennen wieder).
Das ist ziemlich viel, was ich will, aber ich habe Probleme bekommen zu arbeiten. Grundsätzlich mag ich in Biege erkennen und Fehler, und wenn ein Fehler erkannt wird, hat Bison die gesamte Linie verwerfen. Was ich jetzt habe, ist nicht ganz richtig funktioniert, weil meine Befehle immer noch ausgeführt werden soll:
kbsh: ls '/home
Error: Unterminated Single Quote
admin kbrandt tempuser
syntax error
kbsh:
In meiner Bison-Datei:
commands:
/*Empty*/ { prompt(); } |
command { prompt(); }
;
command:
error {return 1; } |
chdir_command |
pwd_command |
exit_command |
WORD arg_list {
execute_command($1, $2);
//printf("%s, %s\n", $1, $2);
} |
WORD { execute_command($1, NULL); }
;
Und in meinem Flex:
' {BEGIN inQuote; }
<inQuote>\n {printf("Error: Unterminated Single Quote\n"); BEGIN(0); return(ERROR);}
Lösung
Ich glaube nicht, dass Sie eine einfache Lösung für den Umgang mit diesen Arten von Parsing-Fehlern in der Lexer finden.
Ich würde die Lexer halten (flex / lex) so dumm wie möglich, es sollte nur einen Strom von Basis Token liefern (Identifikatoren, Schlüsselwörter, etc ...) und haben den Parser (yacc / Bison) tun, um die Fehlererkennung . In der Tat ist es Setup für genau das, was Sie wollen, mit einer kleinen Umstrukturierung Ihres Ansatzes ...
In der Lexer (parser.l), halten Sie es einfach (kein EOL / Newline Handling), so etwas wie (nicht voll ist Sache):
}%
/* I don't recall if the backslashify is required below */
SINGLE_QUOTE_STRING \'.*\'
DOUBLE_QUOTE_STRING \".*\"
%%
{SINGLE_QUOTE_STRING} {
yylval.charstr = copy_to_tmp_buffer(yytext); // implies a %union
return STRING;
}
{DOUBLE_QUOTE_STRING} {
yylval.charstr = copy_to_tmp_buffer(yytext); // implies a %union
return STRING;
}
\n return NEWLINE;
Dann in Ihrem parser.y Datei, die alle realen Umgang tun (nicht voll ist Sache):
command:
error NEWLINE
{ yyclearin; yyerrorok; print_the_next_command_prompt(); }
| chdir_command STRING NEWLINE
{ do_the_chdir($<charstr>2); print_the_next_command_prompt(); }
| ... and so on ...
Es gibt zwei Dinge zu beachten hier:
- Die Verschiebung der Dinge wie NEWLINE auf die yacc Seite, so dass Sie bestimmen können, wenn der Benutzer mit dem Befehl ausgeführt wird, dann können Sie die Dinge klar und neu beginnen (vorausgesetzt, Sie „
int yywrap() {return 1;}
“ irgendwo haben). Wenn Sie versuchen, es zu früh in flex zu erkennen, wenn Sie wissen, um einen Fehler zu erhöhen? - chdir ist nicht ein Befehl (es sei denn, es Unter regiert wurde und Sie haben nur zeigen es nicht), ist es nun chdir_command STRING (das Argument der chdir) hat. Das macht es so, dass der Parser herausfinden kann, was schief gelaufen ist, kann man dann yyerror wenn das Verzeichnis nicht existiert, etc ...
So können Sie so etwas wie (erraten, was Chdir aussehen könnte) bekommen sollte:
cd ‚some_directory
Syntaxfehler
cd 'some_directory'
Sie sind in der some_directory dude!
Und es ist alles durch die yacc grammer gehandhabt wird, nicht von der tokenizer.
Ich habe festgestellt, dass möglichst flex so einfach zu halten gibt Ihnen die meisten *** flex *** bilität. :)