سؤال

أريد إنشاء حلقة طباعة للقراءة باستخدام مرن / Bison Parser. المشكلة هي، Lexer Lexer الذي تم إنشاؤه Flex يريد إدخال ملف النوع * وأود أن يكون سحر *. هل هناك أي طريقة للقيام بذلك؟

تم إنشاء اقتراح واحد لإنشاء أنبوب وأعلافه بالسلسلة وفتح واصف الملف وإرساله إلى Lexer. هذا بسيط إلى حد ما لكنه يشعر بالملفاة وليس منصة مستقلة للغاية. هل هناك طريقة أفضل؟

هل كانت مفيدة؟

المحلول

تتوفر الإجراءات التالية لإعداد مخازن المخازن المؤقتة للمسح الضوئي في سلاسل الذاكرة بدلا من الملفات (كما يفعل yy_create_buffer):

  • YY_BUFFER_STATE yy_scan_string(const char *str): يقوم بمسح سلسلة NUL
  • YY_BUFFER_STATE yy_scan_bytes(const char *bytes, int len): تقوم بمسح بايت Len (بما في ذلك NULS) بدءا من Bytes الموقع

لاحظ أن كلا من هذه الوظائف تنشئ، وإرجاع مقبض YY_BUFFER_STATE YY_BUFFER_STATE (الذي يجب عليك حذفه باستخدام yy_delete_buffer () عند الانتهاء منه) لذا فإن Yylex () مسح نسخة من السلسلة أو البايتات. قد يكون هذا السلوك مرغوبا حارا لأن yylex () يعدل محتويات المخزن المؤقت هو المسح).

إذا كنت تريد تجنب النسخة (و yy_delete_buffer) باستخدام:

  • YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)

عينة الرئيسية:

int main() {
    yy_scan_buffer("a test string");
    yylex();
}

نصائح أخرى

يرى هذا القسم من دليل Flex للحصول على معلومات حول كيفية مسح المخازن المؤقتة في الذاكرة، مثل السلاسل.

ثني يمكن تحليل char * باستخدام أي واحدة من ثلاث وظائف: yy_scan_string(), yy_scan_buffer(), ، و yy_scan_bytes() (انظر توثيق). إليك مثال على الأول:

typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_string(char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);

int main(){
    char string[] = "String to be parsed.";
    YY_BUFFER_STATE buffer = yy_scan_string(string);
    yyparse();
    yy_delete_buffer(buffer);
    return 0;
}

البيانات المكافئة ل yy_scan_buffer() (الذي يتطلب سلسلة مضاعفة غير ذات النهاية):

char string[] = "String to be parsed.\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));

تكرر إجابتي بعض المعلومات التي توفرها DFA و Jlholland، ولكن لا يبدو أن أي من إجاباتهم يعمل من أجلي.

هنا هو ما كنت بحاجة للقيام به:

extern yy_buffer_state;
typedef yy_buffer_state *YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_buffer(char *, size_t);

int main(int argc, char** argv) {

  char tstr[] = "line i want to parse\n\0\0";
  // note yy_scan_buffer is is looking for a double null string
  yy_scan_buffer(tstr, sizeof(tstr));
  yy_parse();
  return 0;
}

لا يمكنك extery the typedef، مما يجعل الشعور عندما تفكر في ذلك.

الجواب المقبول غير صحيح. سوف يسبب تسرب الذاكرة.

داخليا، YY_SCAN_STRING يدعو YY_SCAN_BYTES الذي، بدوره، يستدعي yy_scan_buffer.

yy_scan_bytes يخصص الذاكرة للحصول على نسخة من المخزن المؤقت الإدخال.

yy_scan_buffer يعمل مباشرة على المخزن المؤقت المرفق.

مع جميع النماذج الثلاثة، يجب عليك الاتصال YY_DELETE_BUFFER لتحرير معلومات الحالة العازلة للمرن (YY_BUFFER_STATE).

ومع ذلك، مع yy_scan_buffer، يمكنك تجنب التخصيص الداخلي / النسخ / خالية من المخزن المؤقت الداخلي.

لا يأخذ النموذج الأولي ل YY_SCAN_BUFFER شار إضافي * ويجب ألا تتوقع أن تظل المحتويات دون تغيير.

إذا قمت بتخصيص الذاكرة لعقد السلسلة الخاصة بك، فأنت مسؤول عن تحريرها بعد الاتصال YY_DELETE_BUFFER.

أيضا، لا تنسى أن يكون لديك عودة Yywrap 1 (غير صفرية) عند تحليل هذه السلسلة فقط.

أدناه مثال كامل.

%%

<<EOF>> return 0;

.   return 1;

%%

int yywrap()
{
    return (1);
}

int main(int argc, const char* const argv[])
{
    FILE* fileHandle = fopen(argv[1], "rb");
    if (fileHandle == NULL) {
        perror("fopen");
        return (EXIT_FAILURE);
    }

    fseek(fileHandle, 0, SEEK_END);
    long fileSize = ftell(fileHandle);
    fseek(fileHandle, 0, SEEK_SET);

    // When using yy_scan_bytes, do not add 2 here ...
    char *string = malloc(fileSize + 2);

    fread(string, fileSize, sizeof(char), fileHandle);

    fclose(fileHandle);

    // Add the two NUL terminators, required by flex.
    // Omit this for yy_scan_bytes(), which allocates, copies and
    // apends these for us.   
    string[fileSize] = '\0';
    string[fileSize + 1] = '\0';

    // Our input file may contain NULs ('\0') so we MUST use
    // yy_scan_buffer() or yy_scan_bytes(). For a normal C (NUL-
    // terminated) string, we are better off using yy_scan_string() and
    // letting flex manage making a copy of it so the original may be a
    // const char (i.e., literal) string.
    YY_BUFFER_STATE buffer = yy_scan_buffer(string, fileSize + 2);

    // This is a flex source file, for yacc/bison call yyparse()
    // here instead ...
    int token;
    do {
        token = yylex(); // MAY modify the contents of the 'string'.
    } while (token != 0);

    // After flex is done, tell it to release the memory it allocated.    
    yy_delete_buffer(buffer);

    // And now we can release our (now dirty) buffer.
    free(string);

    return (EXIT_SUCCESS);
}

في الطريقة الأخرى، يمكنك إعادة تعريف الوظيفة yy_input في ملف lex، ثم قم بتعيين السلسلة الخاصة بك إلى إدخال LEX. على النحو التالي:

#undef YY_INPUT
#define YY_INPUT(buf) (my_yyinput(buf))

char my_buf[20];

void set_lexbuf(char *org_str)
{  strcpy(my_buf, org_str);  }

void my_yyinput (char *buf)
{  strcpy(buf, my_buf);      } 

في MAIN.C الخاص بك، قبل المسح الضوئي، تحتاج إلى تعيين المخزن المؤقت ليكس أولا:

set_lexbuf(your_string);
scanning...

فيما يلي مثال صغير لاستخدام Bison / Flex كمحلل داخل رمز CPP الخاص بك لسلسلة تحليل وتغيير قيمة السلسلة وفقا له (تمت إزالة أجزاء قليلة من الرمز، لذلك قد تكون هناك أجزاء غير ذات صلة هناك.)

%{
#include "parser.h"
#include "lex.h"
#include <math.h> 
#include <fstream>
#include <iostream> 
#include <string>
#include <vector>
using namespace std;
 int yyerror(yyscan_t scanner, string result, const char *s){  
    (void)scanner;
    std::cout << "yyerror : " << *s << " - " << s << std::endl;
    return 1;
  }
    %}

%code requires{
#define YY_TYPEDEF_YY_SCANNER_T 
typedef void * yyscan_t;
#define YYERROR_VERBOSE 0
#define YYMAXDEPTH 65536*1024 
#include <math.h> 
#include <fstream>
#include <iostream> 
#include <string>
#include <vector>
}
%output "parser.cpp"
%defines "parser.h"
%define api.pure full
%lex-param{ yyscan_t scanner }
%parse-param{ yyscan_t scanner } {std::string & result}

%union {
  std::string *  sval;
}

%token TOKEN_ID TOKEN_ERROR TOKEN_OB TOKEN_CB TOKEN_AND TOKEN_XOR TOKEN_OR TOKEN_NOT
%type <sval>  TOKEN_ID expression unary_expression binary_expression
%left BINARY_PRIO
%left UNARY_PRIO
%%

top:
expression {result = *$1;}
;
expression:
TOKEN_ID  {$$=$1; }
| TOKEN_OB expression TOKEN_CB  {$$=$2;}
| binary_expression  {$$=$1;}
| unary_expression  {$$=$1;}
;

unary_expression:
 TOKEN_NOT expression %prec UNARY_PRIO {result =  " (NOT " + *$2 + " ) " ; $$ = &result;}
;
binary_expression:
expression expression  %prec BINARY_PRIO {result = " ( " + *$1+ " AND " + *$2 + " ) "; $$ = &result;}
| expression TOKEN_AND expression %prec BINARY_PRIO {result = " ( " + *$1+ " AND " + *$3 + " ) "; $$ = &result;} 
| expression TOKEN_OR expression %prec BINARY_PRIO {result = " ( " + *$1 + " OR " + *$3 + " ) "; $$ = &result;} 
| expression TOKEN_XOR expression %prec BINARY_PRIO {result = " ( " + *$1 + " XOR " + *$3 + " ) "; $$ = &result;} 
;

%%

lexer.l : 

%{
#include <string>
#include "parser.h"

%}
%option outfile="lex.cpp" header-file="lex.h"
%option noyywrap never-interactive
%option reentrant
%option bison-bridge

%top{
/* This code goes at the "top" of the generated file. */
#include <stdint.h>
}

id        ([a-zA-Z][a-zA-Z0-9]*)+
white     [ \t\r]
newline   [\n]

%%
{id}                    {    
    yylval->sval = new std::string(yytext);
    return TOKEN_ID;
}
"(" {return TOKEN_OB;}
")" {return TOKEN_CB;}
"*" {return TOKEN_AND;}
"^" {return TOKEN_XOR;}
"+" {return TOKEN_OR;}
"!" {return TOKEN_NOT;}

{white};  // ignore white spaces
{newline};
. {
return TOKEN_ERROR;
}

%%

usage : 
void parse(std::string& function) {
  string result = "";
  yyscan_t scanner;
  yylex_init_extra(NULL, &scanner);
  YY_BUFFER_STATE state = yy_scan_string(function.c_str() , scanner);
  yyparse(scanner,result);
  yy_delete_buffer(state, scanner);
  yylex_destroy(scanner);
  function = " " + result + " ";  
}

makefile:
parser.h parser.cpp: parser.y
    @ /usr/local/bison/2.7.91/bin/bison -y -d parser.y


lex.h lex.cpp: lexer.l
    @ /usr/local/flex/2.5.39/bin/flex lexer.l

clean:
    - \rm -f *.o parser.h parser.cpp lex.h lex.cpp

هناك هذا الرمز المضحك في Libmatheval:

/* Redefine macro to redirect scanner input from string instead of
 * standard input.  */
#define YY_INPUT( buffer, result, max_size ) \
{ result = input_from_string (buffer, max_size); }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top