使用 Flex/Bison 的解释器 REPL

2023-11-23

我已经为类 C 语言编写了一个解释器,使用 Flex 和 Bison 作为扫描器/解析器。执行完整的程序文件时它工作正常。

现在我正在尝试在解释器中实现 REPL 以供交互式使用。我希望它像 Ruby 或 ML 中的命令行解释器一样工作:

  1. 显示提示
  2. 接受一条或多条语句就行
  3. If the expression is incomplete
    1. 显示继续提示
    2. 允许用户继续输入行
  4. When the line ends with a complete expression
    1. echo 计算最后一个表达式的结果
    2. 显示主提示

我的语法以top_level产生式,代表语言中的单个语句。词法分析器在标准输入上配置为交互模式。我在完整文件和 REPL 模式下使用相同的扫描器和语法,因为这两个界面没有语义差异。

我的主要评估循环的结构如下。

while (!interpreter.done) {
    if (interpreter.repl)
        printf(prompt);
    int status = yyparse(interpreter);
    if (status) {
        if (interpreter.error)
            report_error(interpreter);
    }
    else {
        if (interpreter.repl)
            puts(interpreter.result);
    }
}            

除了提示和回显逻辑之外,这工作得很好。如果用户在一行中输入多个语句,则此循环会打印出多余的提示和表达式。如果表达式在多行上继续,则此代码不会打印出继续提示。出现这些问题是因为提示/回显逻辑的粒度是top_level语法中的语句,但行读取逻辑位于词法分析器的深处。

重构评估循环以处理 REPL 提示和回显的最佳方法是什么?那是:

  • 如何每行显示一个提示
  • 如何在合适的时间显示继续提示
  • 如何判断完整表达式何时是一行中的最后一个

(我不想更改扫描仪语言来传递换行符,因为这会严重改变语法。修改YY_INPUT在 Bison 语法中添加一些动作就可以了。另外,我使用的是 Xcode 附带的库存 Flex 2.5.35 和 Bison 2.3。)


在研究了像 Python 和 SML/NJ 这样的语言如何处理它们的 REPL 后,我在我的解释器中得到了一个很好的结果。我没有将提示/回显逻辑放在最外面的解析器驱动程序循环中,而是将其放在最里面的词法分析器输入例程中。解析器和词法分析器中的操作设置了控制输入例程提示的标志。

我使用的是可重入扫描仪,所以yyextra包含解释器各层之间传递的状态。它看起来大致是这样的:

typedef struct Interpreter {
    char* ps1; // prompt to start statement
    char* ps2; // prompt to continue statement
    char* echo; // result of last statement to display
    BOOL eof; // set by the EOF action in the parser
    char* error; // set by the error action in the parser
    BOOL completeLine // managed by yyread
    BOOL atStart; // true before scanner sees printable chars on line
    // ... and various other fields needed by the interpreter
} Interpreter;

词法分析器输入例程:

size_t yyread(FILE* file, char* buf, size_t max, Interpreter* interpreter)
{
    // Interactive input is signaled by yyin==NULL.
    if (file == NULL) {
        if (interpreter->completeLine) {
            if (interpreter->atStart && interpreter->echo != NULL) {
                fputs(interpreter->echo, stdout);
                fputs("\n", stdout);
                free(interpreter->echo);
                interpreter->echo = NULL;
            }
            fputs(interpreter->atStart ? interpreter->ps1 : interpreter->ps2, stdout);
            fflush(stdout);
        }

        char ibuf[max+1]; // fgets needs an extra byte for \0
        size_t len = 0;
        if (fgets(ibuf, max+1, stdin)) {
            len = strlen(ibuf);
            memcpy(buf, ibuf, len);
            // Show the prompt next time if we've read a full line.
            interpreter->completeLine = (ibuf[len-1] == '\n');
        }
        else if (ferror(stdin)) {
            // TODO: propagate error value
        }
        return len;
    }
    else { // not interactive
        size_t len = fread(buf, 1, max, file);
        if (len == 0 && ferror(file)) {
            // TODO: propagate error value
        }
        return len;
    }
}

顶层解释器循环变为:

while (!interpreter->eof) {
    interpreter->atStart = YES;
    int status = yyparse(interpreter);
    if (status) {
        if (interpreter->error)
            report_error(interpreter);
    }
    else {
        exec_statement(interpreter);
        if (interactive)
            interpreter->echo = result_string(interpreter);
    }
}

Flex 文件获得以下新定义:

%option extra-type="Interpreter*"

#define YY_INPUT(buf, result, max_size) result = yyread(yyin, buf, max_size, yyextra)

#define YY_USER_ACTION  if (!isspace(*yytext)) { yyextra->atStart = NO; }

The YY_USER_ACTION处理语言语法中的标记和输入行之间棘手的相互作用。我的语言类似于 C 和 ML,需要特殊字符 (';') 来结束语句。在输入流中,该字符可以后跟一个换行符以表示行结束,也可以后跟作为新语句一部分的字符。如果自最后一个语句结束以来扫描的唯一字符是换行符或其他空格,则输入例程需要显示主提示;否则应该显示继续提示。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Flex/Bison 的解释器 REPL 的相关文章

  • 如何引用 .net 可执行文件中的类?

    IL 反汇编程序显示了我想在项目中使用的 Net 可执行文件中的类 我如何使用我自己项目中的这些类 从 Visual Studio 上的项目添加对该可执行文件的引用 您应该有权访问它定义的公共类 可执行文件是一个像任何其他程序集一样的程序集
  • 不同文件中的相同静态变量[重复]

    这个问题在这里已经有答案了 HI 欢迎大家回答这个问题 Q1 如果 File1 c 包含 static int a File2 c 包含 static int a 如果这两个文件是同一项目的一部分 如果是的话 编译会抛出任何错误吗 如果它不
  • Hololens 应用程序将不再构建 - 引用元数据文件丢失且找不到 c-Sharp.firstpass

    我已按照 Microsoft 在其多个项目下列出的确切步骤进行操作微软全息 学院 https developer microsoft com en us windows holographic academy教程 我完成了所有这些 并且从创
  • 使用 c11 标准和 clang 来使用 strcpy_s

    我正在运行 OS X Sierra 并尝试编译一个使用的 c 程序strcpy s 但是我安装的 clang 编译器使用的是 c99 标准 但是据我读到的 https embeddedgurus com barr code 2017 08
  • 如何使用平台调用编组 void*

    我需要从 dll 中包含的 C api 调用函数 函数原型如下 int func char name void value 其中指针值的内容可以引用依赖于传递的名称的任何类型 我不确定如何设置 Dll 输入端口以正确编组此 void 我一直
  • Image.FromStream() 方法返回 Invalid Argument 异常

    我正在从智能相机成像器捕获图像 并通过套接字编程从相机接收字节数组 NET 应用程序是客户端 相机是服务器 问题是我在运行时收到 System InvalidArgument 异常 private Image byteArrayToImag
  • 使用 C# 启动 Outlook

    我可以让 C 在代码中启动 Outlook 吗 在 VB6 中 我们使用对象 Outlook Application 并编写 Set oOutlook CreateObject Outlook Application Set oNameSp
  • std::string substr 方法问题

    你好 我正在写这个方法 我希望它从给定缓冲区中提取给定位置的一部分 我有一个像这样的字符串something one something two我想要得到 一个 这是我的想法 static std string Utils getHeade
  • 从 ASP.NET Web API 返回 HTML

    如何从 ASP NET MVC Web API 控制器返回 HTML 我尝试了下面的代码 但由于未定义 Response Write 而出现编译错误 public class MyController ApiController HttpP
  • 在另一个类中使用一个类对象?

    我正在用 c 制作应用程序 在该应用程序中 我有一个类DataCapture cs 在同一个应用程序中 我有另一个类Listner cs 在 Listner cs 类中 我想使用以下对象DataCapture cs不创建新对象DataCap
  • 在运行时生成可执行文件

    好吧 所以我想知道如何创建一个程序 该程序创建第二个程序 就像大多数压缩程序如何创建自解压自可执行文件一样 但这不是我需要的 假设我有 2 个程序 每个都包含一个类 我将使用一个程序来修改类并用数据填充类 第二个文件将是一个也具有该类的程序
  • 如何在不加载到内存的情况下对大型 csv 文件进行排序

    我有 20GB csv 文件 如下所示 CallId MessageNo Information Number 1000 1 a 2 99 2 bs 3 1000 3 g 4 66 2 a 3 20 16 3 b 1000 7 c 4 99
  • 通过 C++ 标头在 C++ 和 C# 中使用枚举

    我有一个用 C 编写的服务器 位于命名管道的末端 嗯 提供服务 可以发送到服务器的命令在位于头文件中的枚举中定义 enum e doThing1 e doThing2 e doLastThing 所需枚举的值被放入发送到服务器的消息的第一个
  • 如何同时正确使用管道和信号?

    我有 2 个孩子 我想将信号从孩子发送到父母 并将答案 随机数 为什么 为什么不 命名管道从父母发送到每个孩子 我有这个代码 include
  • nVidia 和 ATI 之间的 OpenGL 渲染差异

    最近 我将 ATI 驱动程序 我使用的是 HD7970 更新为最新版本 但我的 OpenGL 项目的一些对象停止工作 更重要的是 他们适用于 nVidia 最新驱动程序 在 960m 上测试 ATI 和 nVidia 渲染管道之间有什么我应
  • 偏专业化朋友声明

    在下面的代码中 template
  • TransactionScope 在某些机器上自动升级到 MSDTC?

    在我们的项目中 我们使用 TransactionScope 来确保我们的数据访问层在事务中执行其操作 我们的目标是not要求在我们的最终用户的计算机上启用 MSDTC 服务 问题是 在我们一半的开发人员机器上 我们可以在禁用 MSDTC 的
  • 删除指针后将其设为 NULL 是一个好习惯吗?

    我首先要说的是 使用智能指针 您将永远不必担心这个问题 下面的代码有什么问题 Foo p new Foo use p delete p p NULL 这是由答案和评论 https stackoverflow com questions 19
  • 从 C# 应用程序调用 ASP.net Web 服务

    我有个问题 我如何调用 Web 服务并从 C 桌面应用程序获取结果 我正在制作一个桌面应用程序 我希望它能够连接到我的在线 ASP net Web 服务 这怎么可能 在 解决方案资源管理器 中 右键单击项目节点并选择 添加 Service参
  • System.IO.IOException:进程无法访问文件“.txt”,因为它正在被另一个进程使用

    我正在使用下一个代码来记录 Web 应用程序的错误 using StreamWriter myStream new StreamWriter sLogFilePath true myStream WriteLine string Forma

随机推荐

  • 向方解石添加用户定义的函数

    我需要向 Calcite 添加一个用户定义的函数 该函数接受一个整数作为参数并返回一个整数 public class SquareFunction public int eval int a return a a 创建模式并添加功能的相关代
  • 停止在 ggplot2 注释中解析小数点后的零

    我需要用一条包含 真实 希腊字母和四舍五入到小数点后两位的数字的线来注释 ggplot2 图上的位置 我的问题出现是因为我想显示小数位 即使它们都是零 不幸的是 parse T设置在annotate转换字符串 1 00 into 1 这是一
  • 如何在spring boot api中通过requestbody获取对象列表

    通过以下方式获取对象列表 RequestBody在控制器中并处理每个对象list做一个业务逻辑 我已经尝试过这个但不起作用 RequestMapping value updateservicetype method RequestMetho
  • 转换:未授权 `aaaa` @ error/constitute.c/ReadImage/453

    我想通过使用创建一个验证码图片convert来自 ImageMagick 我跟随this 但也存在一些问题 在我的 linux shell 中输入 convert background white fill black font FreeS
  • Pydev 和 *.pyc 文件

    我使用 Eclipse 4 2 1 和 pydev 插件 版本 2 7 1 进行 python 开发 pydev 似乎对预编译的 python 文件 pyc 文件 有问题 我使用的软件包仅提供此类预编译文件 导入模块时 pydev 显示 未
  • Twig 中 is_array 的等价物

    我正在开发一个模板 我需要检查某些内容是否是数组 我该如何在 Twig 中做到这一点 我试过了 if my var is iterable for v in my var endfor else my var endif 但它总是打印 my
  • 对称交叉连接

    我正在尝试提取所有对说i j从表中的每个元素到同一个表中的每个元素 这里是我的查询 select a Id L b id R into cross from MyTable a cross join mytable b 我现在的情况是i j
  • Angular Material 垫标签可访问性

    我有一个带有文本输入控件的 mat form field 我有一个 mat label 并且还放置了一个 aria label 属性attr aria label直接在输入元素上 Is the mat label屏幕阅读器本身就足够了吗 是
  • 是否可以在 Internet Explorer 中启用 HTTP 基本身份验证?

    一个 URL 例如http username email protected 不适用于 Internet Explorer 如 Microsoft 知识库文章 Internet Explorer 不支持网站地址中的用户名和密码 我找不到合适
  • Android 中的地图标记居中

    我使用以下代码以缩放级别显示单个标记 但它不会使该标记在地图上居中 只会显示一个标记 LatLng latLng new LatLng Latitude Longitude cameraUpdate CameraUpdateFactory
  • Win32 API 函数与 CRT 对应函数(例如 CopyMemory 与 memcpy)

    在编写 Win32 C C 代码时 使用 Windows 特定的函数 如lstrcpyn or CopyMemory而不是相应的 CRT 函数 除了 CRT 函数的可移植性之外 至少有一些 CRT 函数在内部使用 Win32 函数 此外 C
  • 有没有用于生成缩略图的java库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 我需要一些足够智能的缩略图生成库才能在我的 java 应用程序中使用它 我找到了合适的代码here但我不确定可能的许可问题 有免费的合适的图书馆吗
  • 如何在自定义日期时间启动通知?

    我知道如何在一些点击事件后 X 毫秒启动通知 像这样的代码 Timer timer new Timer TimerTask timerTask new TimerTask Override public void run triggerNo
  • 处理 Windows 8 网格中的滑动手势

    我正在尝试实现一个自定义控件 其中包含一个网格 其中一些画布元素作为子元素 当在网格上进行滑动操作时 我打算对画布元素执行一些操作 我无法处理网格的滑动 我已在msdn win8 开发论坛 我和你们的情况一样 因为没有关于如何完成此操作的示
  • JavaScript 检查文件大小

    是否可以继续使用 javascript 检查网络服务器上文件的文件大小 例如http www mysite com myfile js 大于 0 字节 如果是 则返回 true 或 false 值 提前致谢 理论上 您可以使用 XHR 发出
  • Jackson 中不区分大小写的 JsonNode

    我需要反序列化 JSON 对象并以不区分大小写的方式访问字段 例子 String s FOO 123 ObjectMapper mapper new ObjectMapper JsonNode node mapper readTree s
  • 编译gdb进行远程调试

    我正在尝试远程调试在arm9上运行的应用程序 到目前为止 我已经能够在我的设备上交叉编译和执行 gdbserver 获取 gdb 7 2 源代码并提取它们 configure target arm none linux gnueabi wi
  • python matplotlib 热图颜色条从透明

    如何实现这样的python matplotlib heatmap colorbar plt imshow a aspect auto cmap plt cm gist rainbow r plt colorbar matplotlib 库中
  • 当奇数宽度的 div 被分割 50%/50% 时,剩余的 1px 会发生什么?

    假设我想为以下内容制作背景div wrapper这样使用两个 div 一半是蓝色 一半是红色width 50 像这样 HTML div div div div div div CSS body html wrapper width 100
  • 使用 Flex/Bison 的解释器 REPL

    我已经为类 C 语言编写了一个解释器 使用 Flex 和 Bison 作为扫描器 解析器 执行完整的程序文件时它工作正常 现在我正在尝试在解释器中实现 REPL 以供交互式使用 我希望它像 Ruby 或 ML 中的命令行解释器一样工作 显示