【问题标题】:How to make YY_INPUT point to a string rather than stdin in Lex & Yacc (Solaris)如何使 YY_INPUT 指向字符串而不是 Lex & Yacc (Solaris) 中的标准输入
【发布时间】:2009-12-17 09:51:27
【问题描述】:

我希望我的yylex() 解析字符串而不是文件或标准输入。我如何使用 Solaris 提供的 Lex 和 Yacc 来做到这一点?

【问题讨论】:

标签: c solaris yacc lex


【解决方案1】:

重新定义 YY_INPUT。这是一个工作示例,使用命令编译和运行

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

从 globalInputText 读取输入。您可以修改此示例,以便全局输入文本是您想要的任何字符串或来自您想要的任何输入源。

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;
}

【讨论】:

  • numBytesReadmaxBytesToRead 应分别为 unsigned long *unsigned long
【解决方案2】:

如果你使用的是真正的lex 而不是flex 我相信你可以简单地定义你自己的

int input(void);

这可以从字符串中返回字符或任何你想要的。

或者,我相信您可以将字符串写入文件,然后在流yyin 上打开文件。我怀疑这适用于任何一种实现。

如果使用 flex,那么我认为你重新定义了 YY_INPUT() 宏,

【讨论】:

    【解决方案3】:

    另一种方法是使用链接答案中已经提到的 yy_scan_string

    【讨论】:

      【解决方案4】:

      尽管使用 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]
      

      【讨论】:

        【解决方案5】:

        正如之前所说,它可以通过重新定义 input() 来完成 - 我在 aix、hpux 和 solaris 上使用过它。

        或者我也使用的另一种方法是制作管道,并使用fdopen()-ed FILE* 作为yyin

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多