В настоящее время я пытаюсь создать базовую грамматику, которая может принимать и распознавать команды оболочки.Тем не менее, я получаю синтаксические ошибки, которые избегают моего понимания.Я нарисовал дерево и, насколько я могу судить, покрываю все основания.Вот мой файл lex
%{
#include <cstring>
#include "y.tab.hh"
static void yyunput (int c,char *buf_ptr );
void myunputc(int c) {
unput(c);
}
%}
%option noyywrap
%%
return PIPE;
}
"<" {
return LESS;
}
"&" {
return AMP;
}
\n {
return NEWLINE;
}
[ \t] {
/* Discard spaces and tabs */
}
">" {
return GREAT;
}
"2>" {
return TGREAT;
}
">&" {
return GREATAMP;
}
">>" {
return DUBGREAT;
}
">>&" {
return DUBGREATAMP;
}
[^ \t\n][^ \t\n]* {
/* Assume that file names have only alpha chars */
yylval.cpp_string = new std::string(yytext);
return WORD;
}
А вот мой файл yacc
%code requires
{
#include <string>
#if __cplusplus > 199711L
#define register // Deprecated in C++11 so remove the keyword
#endif
}
%union
{
char *string_val;
// Example of using a c++ type in yacc
std::string *cpp_string;
}
%token <cpp_string> WORD
%token NOTOKEN GREAT NEWLINE PIPE LESS AMP TGREAT GREATAMP DUBGREAT DUBGREATAMP
%{
//#define yylex yylex
#include <cstdio>
#include "shell.hh"
void yyerror(const char * s);
int yylex();
%}
%%
goal:
command_list
;
command_list:
command_line
| command_list command_line
;
command_line:
pipe_list io_modifier_list background_optional NEWLINE
| NEWLINE
| error NEWLINE{yyerrok;}
;
pipe_list:
pipe_list PIPE command_and_args
| command_and_args
;
command_and_args:
command_word argument_list {
Shell::_currentCommand.
insertSimpleCommand( Command::_currentSimpleCommand );
}
;
argument_list:
argument_list argument
| /* can be empty */
;
io_modifier_list:
io_modifier_list iomodifier_opt
| /*empty*/
;
iomodifier_opt:
GREAT WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
}
| DUBGREAT WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
}
| DUBGREATAMP WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
Shell::_currentCommand._background = true;
}
| GREATAMP WORD {
printf(" Yacc: insert output \"%s\"\n", $2->c_str());
Shell::_currentCommand._outFile = $2;
Shell::_currentCommand._background = true;
}
| LESS WORD {
printf(" Yacc: insert input \"%s\"\n", $2->c_str());
Shell::_currentCommand._inFile = $2;
}
| /* can be empty */
;
background_optional:
AMP {
Shell::_currentCommand._background = true;
}
| /*empty*/
;
argument:
WORD {
printf(" Yacc: insert argument \"%s\"\n", $1->c_str());
Command::_currentSimpleCommand->insertArgument( $1 );
}
;
command_word:
WORD {
printf(" Yacc: insert command \"%s\"\n", $1->c_str());
Command::_currentSimpleCommand = new SimpleCommand();
Command::_currentSimpleCommand->insertArgument( $1 );
}
;
%%
void
yyerror(const char * s)
{
fprintf(stderr,"%s", s);
}
#if 0
main()
{
yyparse();
}
#endif
В простейшем случае я попытался ls -al
.В моем понимании ls распознается как command_word.Затем -al признается в качестве аргумента.Это создает новый список аргументов, содержащий только -al.Оттуда, command_and_args создается из command_word ls и arguments_list -al.Это создает pipe_list, который содержит только этот command_and_args.Оттуда создается command_line с этим новым pipe_list, пустым io_modifier_list, пустым background_optional и символом новой строки, когда я нажимаю enter.Это создает список команд, который является целью.Однако мое понимание, по-видимому, неверно, потому что я получаю синтаксическую ошибку, и я надеялся, что кто-то может помочь мне исправить это отсутствие понимания.