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);}
War es hilfreich?

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:

  1. 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?
  2. 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. :)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top