在另一个文件中使用 lex 生成的源代码

发布于 2024-12-13 18:18:12 字数 427 浏览 0 评论 0原文

我想在我拥有的另一个代码中使用 lex 生成的代码,但我看到的所有示例都是将 main 函数嵌入到 lex 文件中,而不是相反。

是否可以使用(包含)从 lex 生成的 c 文件到其他代码中以获得类似的内容(不一定相同)?

#include<something>
int main(){
    Lexer l = Lexer("some string or input file");
    while (l.has_next()){
        Token * token = l.get_next_token();
        //somecode
    }
    //where token is just a simple object to hold the token type and lexeme
    return 0;
}

i would like to use the code generated by lex in another code that i have , but all the examples that i have seen is embedding the main function inside the lex file not the opposite.

is it possible to use(include) the c generated file from lex into other code that to have something like this (not necessarily the same) ?

#include<something>
int main(){
    Lexer l = Lexer("some string or input file");
    while (l.has_next()){
        Token * token = l.get_next_token();
        //somecode
    }
    //where token is just a simple object to hold the token type and lexeme
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

枕花眠 2024-12-20 18:18:12

这就是我要开始的:
注意:这是使用C接口的示例
要使用 C++ 接口,请添加 %option c++ 请参阅下面的

Test.lex

IdentPart1      [A-Za-z_]
Identifier      {IdentPart1}[A-Za-z_0-9]*
WHITESPACE      [ \t\r\n]

%option noyywrap

%%

{Identifier}      {return 257;}
{WHITESPACE}      {/* Ignore */}
.                 {return 258;}

%%

// This is the bit you want.
// It is best just to put this at the bottom of the lex file
// By default functions are extern. So you can create a header file with
// these as extern then included that header file in your code (See Lexer.h)
void* setUpBuffer(char const* text)
{
    YY_BUFFER_STATE buffer  = yy_scan_string(text);
    yy_switch_to_buffer(buffer);

    return buffer;
}

void tearDownBuffer(void* buffer)
{
    yy_delete_buffer((YY_BUFFER_STATE)buffer);
}

Lexer.h

#ifndef LOKI_A_LEXER_H
#define LOKI_A_LEXER_H

#include <string>

extern int   yylex();
extern char* yytext;
extern int   yyleng;

// Here is the interface to the lexer you set up above
extern void* setUpBuffer(char const* text);
extern void  tearDownBuffer(void* buffer);


class Lexer
{
    std::string         token;
    std::string         text;
    void*               buffer;
    public:
    Lexer(std::string const& t)
        : text(t)
    {
        // Use the interface to set up the buffer
        buffer  = setUpBuffer(text.c_str());
    }
    ~Lexer()
    {
        // Tear down your interface
        tearDownBuffer(buffer);
    }
    // Don't use RAW pointers
    // This is only a quick and dirty example.
    bool  nextToken()
    {
        int val = yylex();
        if (val != 0)
        {
            token = std::string(yytext, yyleng);
        }
        return val;
    }
    std::string const& theToken() const {return token;}
};

#endif

main.cpp

#include "Lexer.h"
#include <iostream>

int main()
{
    Lexer l("some string or input file");


    // Did not like your hasToken() interface.
    // Just call nextToken() until it fails.
    while (l.nextToken())
    {
        std::cout << l.theToken() << "\n";
        delete token;
    }
    //where token is just a simple object to hold the token type and lexeme
    return 0;
}

构建

> flext test.lex
> g++ main.cpp  lex.yy.c
> ./a.out
some
string
or
input
file
>

或者,您可以使用 C++ 接口来 flex(其实验性)

test.lext

%option c++


IdentPart1      [A-Za-z_]
Identifier      {IdentPart1}[A-Za-z_0-9]*
WHITESPACE      [ \t\r\n]

%%

{Identifier}      {return 257;}
{WHITESPACE}      {/* Ignore */}
.                 {return 258;}

%%

// Note this needs to be here
// If you define no yywrap() in the options it gets added to the header file
// which leads to multiple definitions if you are not careful.
int yyFlexLexer::yywrap()   { return 1;}

main.cpp

#include "MyLexer.h"
#include <iostream>
#include <sstream>

int main()
{
    std::istringstream  data("some string or input file");
    yyFlexLexer l(&data, &std::cout);


    while (l.yylex())
    {
        std::cout << std::string(l.YYText(), l.YYLeng()) << "\n";
    }
    //where token is just a simple object to hold the token type and lexeme
    return 0;
}

构建

> flex --header-file=MyLexer.h test.lex
> g++ main.cpp lex.yy.cc
> ./a.out
some
string
or
input
file
>

This is what I would start with:
Note: this is an example of using a C interface
To use the C++ interface add %option c++ See below

Test.lex

IdentPart1      [A-Za-z_]
Identifier      {IdentPart1}[A-Za-z_0-9]*
WHITESPACE      [ \t\r\n]

%option noyywrap

%%

{Identifier}      {return 257;}
{WHITESPACE}      {/* Ignore */}
.                 {return 258;}

%%

// This is the bit you want.
// It is best just to put this at the bottom of the lex file
// By default functions are extern. So you can create a header file with
// these as extern then included that header file in your code (See Lexer.h)
void* setUpBuffer(char const* text)
{
    YY_BUFFER_STATE buffer  = yy_scan_string(text);
    yy_switch_to_buffer(buffer);

    return buffer;
}

void tearDownBuffer(void* buffer)
{
    yy_delete_buffer((YY_BUFFER_STATE)buffer);
}

Lexer.h

#ifndef LOKI_A_LEXER_H
#define LOKI_A_LEXER_H

#include <string>

extern int   yylex();
extern char* yytext;
extern int   yyleng;

// Here is the interface to the lexer you set up above
extern void* setUpBuffer(char const* text);
extern void  tearDownBuffer(void* buffer);


class Lexer
{
    std::string         token;
    std::string         text;
    void*               buffer;
    public:
    Lexer(std::string const& t)
        : text(t)
    {
        // Use the interface to set up the buffer
        buffer  = setUpBuffer(text.c_str());
    }
    ~Lexer()
    {
        // Tear down your interface
        tearDownBuffer(buffer);
    }
    // Don't use RAW pointers
    // This is only a quick and dirty example.
    bool  nextToken()
    {
        int val = yylex();
        if (val != 0)
        {
            token = std::string(yytext, yyleng);
        }
        return val;
    }
    std::string const& theToken() const {return token;}
};

#endif

main.cpp

#include "Lexer.h"
#include <iostream>

int main()
{
    Lexer l("some string or input file");


    // Did not like your hasToken() interface.
    // Just call nextToken() until it fails.
    while (l.nextToken())
    {
        std::cout << l.theToken() << "\n";
        delete token;
    }
    //where token is just a simple object to hold the token type and lexeme
    return 0;
}

Build

> flext test.lex
> g++ main.cpp  lex.yy.c
> ./a.out
some
string
or
input
file
>

Alternatively you can use the C++ interface to flex (its experimental)

test.lext

%option c++


IdentPart1      [A-Za-z_]
Identifier      {IdentPart1}[A-Za-z_0-9]*
WHITESPACE      [ \t\r\n]

%%

{Identifier}      {return 257;}
{WHITESPACE}      {/* Ignore */}
.                 {return 258;}

%%

// Note this needs to be here
// If you define no yywrap() in the options it gets added to the header file
// which leads to multiple definitions if you are not careful.
int yyFlexLexer::yywrap()   { return 1;}

main.cpp

#include "MyLexer.h"
#include <iostream>
#include <sstream>

int main()
{
    std::istringstream  data("some string or input file");
    yyFlexLexer l(&data, &std::cout);


    while (l.yylex())
    {
        std::cout << std::string(l.YYText(), l.YYLeng()) << "\n";
    }
    //where token is just a simple object to hold the token type and lexeme
    return 0;
}

build

> flex --header-file=MyLexer.h test.lex
> g++ main.cpp lex.yy.cc
> ./a.out
some
string
or
input
file
>
你怎么敢 2024-12-20 18:18:12

当然。我不确定生成的类;我们使用C生成的
解析器,并从 C++ 调用它们。或者您可以插入任何类型的包装纸
lex 文件中您想要的代码,并从外部调用任何内容
生成的文件。

Sure. I'm not sure about the generated class; we use the C generated
parsers, and call them from C++. Or you can insert any sort of wrapper
code you want in the lex file, and call anything there from outside of
the generated file.

久伴你 2024-12-20 18:18:12

关键字是%option reentrant%option c++

作为示例,这里是ncr2a扫描仪

/** ncr2a_lex.l: Replace all NCRs by corresponding printable ASCII characters. */
%%
&#(1([01][0-9]|2[0-6])|3[2-9]|[4-9][0-9]); { /* accept 32..126 */
  /** `+2` skips '&#', `atoi()` ignores ';' at the end */
  fputc(atoi(yytext + 2), yyout); /* non-recursive version */
}

扫描码可以保持不变。

这里是使用它的程序:

/** ncr2a.c */
#include "ncr2a_lex.h"  

typedef struct {
  int i,j; /** put here whatever you need to keep extra state */
} State; 

int main () {
  yyscan_t scanner;
  State my_custom_data = {0,0};

  yylex_init(&scanner);
  yyset_extra(&my_custom_data, scanner);

  yylex(scanner);

  yylex_destroy(scanner);
  return 0;
}

构建 ncr2a 可执行文件:

flex -R -oncr2a_lex.c --header-file=ncr2a_lex.h ncr2a_lex.l 
cc -c -o ncr2a_lex.o ncr2a_lex.c
cc -o ncr2a ncr2a_lex.o ncr2a.c -lfl

示例

$ echo 'three colons :::' | ./ncr2a
three colons :::

此示例使用 stdin/stdout 作为输入/输出,并调用 yylex() 一次。

要从文件中读取:

yyin = fopen("input.txt", "r" );

@Loki Astari 的答案 显示如何从字符串中读取 (buffer = yy_scan_string(text, Scanner); yy_switch_to_buffer(buffer,扫描仪)

要为每个令牌调用一次 yylex(),请在规则定义中添加 return,以在 *.l 文件中生成完整令牌。

The keywords are %option reentrant or %option c++.

As an example here's the ncr2a scanner:

/** ncr2a_lex.l: Replace all NCRs by corresponding printable ASCII characters. */
%%
&#(1([01][0-9]|2[0-6])|3[2-9]|[4-9][0-9]); { /* accept 32..126 */
  /** `+2` skips '&#', `atoi()` ignores ';' at the end */
  fputc(atoi(yytext + 2), yyout); /* non-recursive version */
}

The scanner code can be left unchanged.

Here the program that uses it:

/** ncr2a.c */
#include "ncr2a_lex.h"  

typedef struct {
  int i,j; /** put here whatever you need to keep extra state */
} State; 

int main () {
  yyscan_t scanner;
  State my_custom_data = {0,0};

  yylex_init(&scanner);
  yyset_extra(&my_custom_data, scanner);

  yylex(scanner);

  yylex_destroy(scanner);
  return 0;
}

To build ncr2a executable:

flex -R -oncr2a_lex.c --header-file=ncr2a_lex.h ncr2a_lex.l 
cc -c -o ncr2a_lex.o ncr2a_lex.c
cc -o ncr2a ncr2a_lex.o ncr2a.c -lfl

Example

$ echo 'three colons :::' | ./ncr2a
three colons :::

This example uses stdin/stdout as input/output and it calls yylex() once.

To read from a file:

yyin = fopen("input.txt", "r" );

@Loki Astari's answer shows how to read from a string (buffer = yy_scan_string(text, scanner); yy_switch_to_buffer(buffer, scanner))
.

To call yylex() once for each token add return inside rule definitions that yield full token in the *.l file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文