2

我正在用 C++ 编程,但不确定如何实现以下目标:

我正在将文件流复制到内存中(因为有人要求我这样做,我更喜欢从流中读取),然后尝试访问它的值以将它们存储到字符串和 int 变量中。

这是为了创建一个解释器。我将尝试解释的代码是(即):

10 PRINT A
20 GOTO 10

这只是一个简单的示例代码。现在这些值将首先存储在“映射”结构中,稍后在“解释”所有内容时访问。要存储的值是:

int lnum // 行号

string cmd // 命令(PRINT 和 GOTO)

string exp // 表达式(在本例中为 A 和 10,但可以包含 (a*b)-c 之类的表达式)

问题给出了以下代码,我如何访问这些值并将它们存储在内存中?exp 字符串的大小也是可变的(可以只是一个变量或一个表达式),所以我不确定如何读取它并将其存储在字符串中。

代码:


#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <map>
#include <sstream>

using namespace std;

 #include "main.hh"


int main () 
{
    int lenght;
    char *buffer;

// get file directory
    string dir;
    cout << "Please drag and drop here the file to interpret: ";
    getline (cin,dir);
    cout << "Thank you.\n";
    cout << "Please wait while your file is being interpreted.\n \n";

// Open File
    ifstream p_prog;
    p_prog.open (dir.c_str());

// Get file size
    p_prog.seekg (0, ios::end);
    lenght = p_prog.tellg();
    p_prog.seekg(0, ios::beg);

// Create buffer and copy stream to it
    buffer = new char[lenght];
    p_prog.read (buffer,lenght);
    p_prog.close();

// Define map<int, char>
    map<int, string> program;
    map<int, string>::iterator iter;


/***** Read File *****/
    int lnum; // line number
    string cmd; // store command (goto, let, etc...)
    string exp; // to be subst with expr. type inst.

//  this is what I had in mind but not sure how to use it properly
//  std::stringstream buffer;
//  buffer >> lnum >> cmd >> exp;

    program [lnum] = cmd; // store values in map




// free memory from buffer, out of scope
    delete[] buffer;
    return 0;
}

我希望这很清楚。

谢谢您的帮助。

瓦莱里奥

4

4 回答 4

11

std::stringstream假设您已经知道类型,您可以使用 a来提取令牌。

对于解释器,我强烈建议使用实际的解析器而不是自己编写。Boost 的XPressive库或ANTLR运行良好。您可以在解析语法或简单地构建 AST 时使用语义操作来构建解释器原语。

另一种选择是 Flex & Bison。基本上,这些都是解析预定义语法的工具。你可以建立自己的,但要为挫折做好准备。递归地平衡括号或强制操作顺序(例如,在乘法之前除法)并非易事。

原始 C++ 解析方法如下:


#include <sstream>
#include <string>

// ... //

istringstream iss(buffer);
int a, b;
string c, d;

iss >> a;
iss >> b;
iss >> c;
iss >> d;

于 2009-12-10T18:49:53.423 回答
1

不要显式地使用向量来动态分配缓冲区。
这使得内存管理隐含。

// Create buffer and copy stream to it   
std::vector<char>   buffer(lenght);
p_prog.read (&buffer[0],lenght);
p_prog.close();

就我个人而言,我没有明确使用 close() (除非我想捕获异常)。只需在一个范围内打开一个文件,该文件将导致析构函数在超出范围时关闭该文件。

于 2009-12-10T18:49:37.107 回答
1

可以完成这样的事情的方式(尤其是您提到的算术表达式部分)是:

  • 编写一些代码来确定令牌在哪里结束和开始。例如5or+将被称为令牌。您可以扫描文本以查找这些或常见的分隔符,例如空格。
  • 写下你正在解析的语言的语法。例如,您可能会写:
    表达式 -> 值
    表达式 -> 表达式 + 表达式
    表达式 -> 表达式 * 表达式
    表达式 -> 函数(表达式)
    表达式 -> ( 表达式 )

然后基于此语法,您将编写一些将表达式标记解析为树的东西。

所以你可能有一棵看起来像这样的树(请原谅 ASCII 艺术)

            +
          / \
         5 *
              / \
             × 3

这表示表达式 5 + (x * 3)。通过在树结构中使用它,可以很容易地评估代码中的表达式:您可以递归地下降树,以子节点作为参数执行操作。

请参阅以下维基百科文章:

或咨询您当地的计算机科学部门。:-)

还有一些工具可以根据语法为您生成这些解析器。您可以搜索“解析器生成器”。

于 2009-12-10T18:51:36.090 回答
0

这可能会有所帮助:

http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html

特别是第 7.3 节。

您最好只 <<' 输入行而不是搜索和字符缓冲区路由。

于 2009-12-10T18:48:36.597 回答