How to make YY_INPUT point to a string rather than stdin in Lex & Yacc (Solaris)

后端 未结 5 795
礼貌的吻别
礼貌的吻别 2020-12-01 16:55

I want my yylex() to parse a string rather than a file or standard input. How can I do it with the Lex and Yacc provided with Solaris?

相关标签:
5条回答
  • Redefine YY_INPUT. Here's a working example, compile and run with the commands

    yacc -d parser.y
    lex lexer.l
    gcc -o myparser *.c
    

    Input is read from globalInputText. You can modify this example so that global input text is whatever string you want or from any input source you want.

    parser.y:

    %{
    #include <stdio.h>
    extern void yyerror(char* s);
    extern int yylex();
    extern int readInputForLexer(char* buffer,int *numBytesRead,int maxBytesToRead);
    %}
    
    %token FUNCTION_PLUS FUNCTION_MINUS NUMBER
    
    %%
    
    expression:
        NUMBER FUNCTION_PLUS NUMBER { printf("got expression!  Yay!\n"); }
        ;
    
    %%
    

    lexer.l:

    %{
    
    #include "y.tab.h"
    #include <stdio.h>
    
    
    #undef YY_INPUT
    #define YY_INPUT(b,r,s) readInputForLexer(b,&r,s)
    
    %}
    
    DIGIT   [0-9]
    %%
    
    \+      { printf("got plus\n"); return FUNCTION_PLUS; }
    \-      { printf("got minus\n"); return FUNCTION_MINUS; }
    {DIGIT}* { printf("got number\n"); return NUMBER; }
    %%
    
    
    void yyerror(char* s) {
        printf("error\n");
    }
    
    int yywrap() {
        return -1;
    }
    

    myparser.c:

    #include <stdio.h>
    #include <string.h>
    
    int yyparse();
    int readInputForLexer( char *buffer, int *numBytesRead, int maxBytesToRead );
    
    static int globalReadOffset;
    // Text to read:
    static const char *globalInputText = "3+4";
    
    int main() {
        globalReadOffset = 0;
        yyparse();
        return 0;
    }
    
    int readInputForLexer( char *buffer, int *numBytesRead, int maxBytesToRead ) {
        int numBytesToRead = maxBytesToRead;
        int bytesRemaining = strlen(globalInputText)-globalReadOffset;
        int i;
        if ( numBytesToRead > bytesRemaining ) { numBytesToRead = bytesRemaining; }
        for ( i = 0; i < numBytesToRead; i++ ) {
            buffer[i] = globalInputText[globalReadOffset+i];
        }
        *numBytesRead = numBytesToRead;
        globalReadOffset += numBytesToRead;
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-01 17:12

    As was said before it can be done through redefining the input() - i've used it on aix, hpux and solaris.

    Or another approach i use too is to make a pipe, and use fdopen()-ed FILE* as yyin.

    0 讨论(0)
  • 2020-12-01 17:32

    If you are using the real lex and not flex I believe you can simply define your own

    int input(void);
    

    This can return characters from a string or whatever you want.

    Alternatively, I believe you could write the string to a file, and open the file on stream yyin. I suspect this would work with either implementation.

    If using flex then I think you redefine the YY_INPUT() macro,

    0 讨论(0)
  • 2020-12-01 17:32

    Here is something that should work with any implementation, although risky by using popen.

    $ cat a.l
    %%
    "abc" {printf("got ABC\n");}
    "def" {printf("got DEF\n");}
    . {printf("got [%s]\n", yytext);}
    %%
    int main(int argc, char **argv)
    {
        return(lex("abcdefxyz"));
    }
    lex(char *s)
    {
        FILE *fp;
        char *cmd;
        cmd=malloc(strlen(s)+16);
        sprintf(cmd, "/bin/echo %s", s); // major vulnerability here ...
        fp=popen(cmd, "r");
        dup2(fileno(fp), 0);
        return(yylex());
    }
    yywrap()
    {
        exit(0);
    }
    $ ./a
    got ABC
    got DEF
    got [x]
    got [y]
    got [z]
    
    0 讨论(0)
  • 2020-12-01 17:35

    another approach is to use yy_scan_string as already mentioned in linked answers

    0 讨论(0)
提交回复
热议问题