简体   繁体   English

如何在flex-lexer中使用GNU readline?

[英]How to use GNU readline with flex-lexer?

I think that using the GNU Readline library for a command-line prompt is good and I want that functionality for my shell that I'm working on. 我认为使用GNU Readline库进行命令行提示很好,我想要我正在使用的shell的功能。 Now readline works for me (my environment is CLion, CMake, Ubuntu, BSD, C, flex-lexer and lemon-parser) but I also need flex and yacc to work at the same time to scan and parse the input but the codes seem "incompatible" - are they really? 现在readline适合我(我的环境是CLion,CMake,Ubuntu,BSD,C,flex-lexer和lemon-parser)但是我还需要flex和yacc同时工作来扫描和解析输入,但代码似乎“不相容” - 他们真的吗?

    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, "\'\0")) {
                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");
    }

The above code has the parsing and scanning working and commented out the readline functionality that won't work if I want both at the same time. 上面的代码有解析和扫描工作,并注释掉readline功能,如果我想同时使用它们将无法工作。 Can I make it work? 我可以让它运作吗?

Read documentation of GNU readline . 阅读GNU readline的文档。 Read the tty demystified page. 阅读tty揭秘页面。 You'll want to use readline only when your stdin is a tty, so use isatty(3) as isatty(STDIN_FILENO) to detect that. 只有当你的stdin是tty时你才会想要使用readline ,所以使用isatty(3) isatty(STDIN_FILENO)来检测它。

The basic behavior of a shell using readline is simply to use the 使用readline的shell的基本行为就是使用

char *readline (const char *prompt);

function. 功能。 So you want to adapt your parser to read from a buffer, not from stdin . 因此,您希望调整解析器以从缓冲区读取,而不是从stdin读取。 This is usual practice. 这是通常的做法。 Don't forget to test (against failure) your call to readline and to free the resulting buffer when you are done. 不要忘记测试(防止失败)对readline的调用并在完成后free生成的缓冲区。

Then, you want to add some completion . 然后,您想要添加一些完成 That is the hard part. 那是困难的部分。 Look at what other shells ( zsh , bash , fish ...) are doing, at least for inspiration. 看看其他贝壳( zshbashfish ......)正在做什么,至少是为了灵感。 Notice that the default file-name completion could be enough, at least when starting. 请注意,默认文件名完成可能就足够了,至少在启动时是这样。

BTW, I won't use both lemon and bison to parse the same input. 顺便说一下,我不会同时使用柠檬野牛来解析相同的输入。 Actually, for a shell (since its syntax is quite simple), I'll just use some hand-written recursive-descent parser . 实际上,对于shell(因为它的语法很简单),我只会使用一些手写的递归下降解析器

flex+readline example flex + readline示例

Following a quick flex "shell" that just can ls and date 继快速柔性“空壳”,它只是可以lsdate

%{
  #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]+     {}
%%

build it with: 建立它:

flex mysh.fl
cc -o mysh lex.yy.c -lreadline -lfl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM