如何将 GNU readline 与 flex-lexer 一起使用?
How to use GNU readline with flex-lexer?
我认为将 GNU Readline 库用于命令行提示很好,我希望我的 shell 能够使用该功能。现在 readline 对我有用(我的环境是 CLion、CMake、Ubuntu、BSD、C、flex-lexer 和 lemon-parser)但是我还需要 flex 和 yacc 同时工作来扫描和解析输入但是代码看起来 "incompatible" - 是真的吗?
params[0] = NULL;
printf("> ");
i=1;
do {
lexCode = yylex(scanner);
/* snprintf(shell_prompt, sizeof(shell_prompt), "%s:%s $ ", getenv("USER"), getcwd(NULL, 1024));
Display prompt and read input (NB: input must be freed after use)...*/
text = strdup(yyget_text(scanner));
/*
input = readline(text);
if (!input)
break;
add_history(input);
free(input);*/
printf("lexcode %i Text %s\n", lexCode, text);
if (lexCode == 4) {
params[i++] = mystring;
if (strcmp(text, "\'[=10=]")) {
params[i++] = mystring;
}
} else
if (lexCode != EOL) {
params[i++] = text;
printf("B%s\n", text);
}
Parse(shellParser, lexCode, text);
if (lexCode == EOL) {
dump_argv("Before exec_arguments", i, params);
exec_arguments(i, params);
corpse_collector();
Parse(shellParser, 0, NULL);
i=1;
}
} while (lexCode > 0);
if (-1 == lexCode) {
fprintf(stderr, "The scanner encountered an error.\n");
}
上面的代码具有解析和扫描功能,并注释掉了如果我同时需要两者将无法使用的 readline 功能。我可以让它工作吗?
阅读 GNU readline. Read the tty demystified page. You'll want to use readline
only when your stdin is a tty, so use isatty(3) 的文档作为 isatty(STDIN_FILENO)
来检测。
shell 使用 readline
的基本行为就是简单地使用
char *readline (const char *prompt);
函数。所以你想调整你的解析器以从缓冲区读取,而不是从 stdin
。这是通常的做法。完成后,不要忘记测试(防止失败)您对 readline
和 free
结果缓冲区的调用。
然后,你想补充一些completion. That is the hard part. Look at what other shells (zsh
, bash
, fish
...) 正在做的事情,至少是为了灵感。请注意,默认文件名完成可能就足够了,至少在开始时是这样。
顺便说一句,我不会同时使用 lemon 和 bison 来解析相同的输入。实际上,对于 shell(因为它的语法很简单),我将使用一些手写的 recursive-descent parser.
flex+readline 示例
跟随快速弯曲“shell”,可以 ls
和 date
%{
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#define YY_INPUT(buf,result,max_size) result = mygetinput(buf, max_size);
static int mygetinput(char *buf, int size) {
char *line;
if (feof(yyin)) return YY_NULL;
line = readline("> ");
if(!line) return YY_NULL;
if(strlen(line) > size-2){
fprintf(stderr,"input line too long\n"); return YY_NULL; }
sprintf(buf,"%s\n",line);
add_history(line);
free(line);
return strlen(buf);
}
%}
%option noyywrap
%%
ls.* system(yytext);
date.* system(yytext);
.+ fprintf(stderr, "Error: unknown comand\n");
[ \t\n]+ {}
%%
构建它:
flex mysh.fl
cc -o mysh lex.yy.c -lreadline -lfl
我认为将 GNU Readline 库用于命令行提示很好,我希望我的 shell 能够使用该功能。现在 readline 对我有用(我的环境是 CLion、CMake、Ubuntu、BSD、C、flex-lexer 和 lemon-parser)但是我还需要 flex 和 yacc 同时工作来扫描和解析输入但是代码看起来 "incompatible" - 是真的吗?
params[0] = NULL;
printf("> ");
i=1;
do {
lexCode = yylex(scanner);
/* snprintf(shell_prompt, sizeof(shell_prompt), "%s:%s $ ", getenv("USER"), getcwd(NULL, 1024));
Display prompt and read input (NB: input must be freed after use)...*/
text = strdup(yyget_text(scanner));
/*
input = readline(text);
if (!input)
break;
add_history(input);
free(input);*/
printf("lexcode %i Text %s\n", lexCode, text);
if (lexCode == 4) {
params[i++] = mystring;
if (strcmp(text, "\'[=10=]")) {
params[i++] = mystring;
}
} else
if (lexCode != EOL) {
params[i++] = text;
printf("B%s\n", text);
}
Parse(shellParser, lexCode, text);
if (lexCode == EOL) {
dump_argv("Before exec_arguments", i, params);
exec_arguments(i, params);
corpse_collector();
Parse(shellParser, 0, NULL);
i=1;
}
} while (lexCode > 0);
if (-1 == lexCode) {
fprintf(stderr, "The scanner encountered an error.\n");
}
上面的代码具有解析和扫描功能,并注释掉了如果我同时需要两者将无法使用的 readline 功能。我可以让它工作吗?
阅读 GNU readline. Read the tty demystified page. You'll want to use readline
only when your stdin is a tty, so use isatty(3) 的文档作为 isatty(STDIN_FILENO)
来检测。
shell 使用 readline
的基本行为就是简单地使用
char *readline (const char *prompt);
函数。所以你想调整你的解析器以从缓冲区读取,而不是从 stdin
。这是通常的做法。完成后,不要忘记测试(防止失败)您对 readline
和 free
结果缓冲区的调用。
然后,你想补充一些completion. That is the hard part. Look at what other shells (zsh
, bash
, fish
...) 正在做的事情,至少是为了灵感。请注意,默认文件名完成可能就足够了,至少在开始时是这样。
顺便说一句,我不会同时使用 lemon 和 bison 来解析相同的输入。实际上,对于 shell(因为它的语法很简单),我将使用一些手写的 recursive-descent parser.
flex+readline 示例
跟随快速弯曲“shell”,可以 ls
和 date
%{
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#define YY_INPUT(buf,result,max_size) result = mygetinput(buf, max_size);
static int mygetinput(char *buf, int size) {
char *line;
if (feof(yyin)) return YY_NULL;
line = readline("> ");
if(!line) return YY_NULL;
if(strlen(line) > size-2){
fprintf(stderr,"input line too long\n"); return YY_NULL; }
sprintf(buf,"%s\n",line);
add_history(line);
free(line);
return strlen(buf);
}
%}
%option noyywrap
%%
ls.* system(yytext);
date.* system(yytext);
.+ fprintf(stderr, "Error: unknown comand\n");
[ \t\n]+ {}
%%
构建它:
flex mysh.fl
cc -o mysh lex.yy.c -lreadline -lfl