Я хочу, чтобы мой yylex()
анализировал строку, а не файл или стандартный ввод. Как я могу сделать это с помощью Lex и Yacc, предоставляемых Solaris?
Как заставить YY_INPUT указывать на строку, а не на stdin в Lex & Yacc (Solaris)
Ответ 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;
}
Ответ 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
.