std::stringstream для чтения целых и строк из строки

Я программирую на С++ и не знаю, как добиться следующего:

Я копирую файловый поток в память (потому что меня попросили, я бы предпочел читать из потока), а затем пытаюсь получить доступ к его значениям, чтобы сохранить их в строки и переменные типа 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;
}

Я надеюсь, что это ясно.

Спасибо за помощь.

Валерио


person Val    schedule 10.12.2009    source источник


Ответы (4)


Вы можете использовать std::stringstream для извлечения токенов, предполагая, что вы уже знаете тип.

Для интерпретатора я настоятельно рекомендую использовать настоящий синтаксический анализатор, а не писать свой собственный. Библиотека 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;

person pestilence669    schedule 10.12.2009

Можно сделать что-то подобное (особенно часть арифметического выражения, на которую вы ссылались):

  • Напишите код, определяющий, где заканчивается и начинается токен. Например, 5 или + будет называться токеном. Вы можете сканировать текст на наличие этих или общих разделителей, таких как пробелы.
  • Напишите грамматику языка, который вы анализируете. Например, вы можете написать:
    expression -> value
    expression -> expression + expression
    expression -> expression * expression
    expression -> function ( expression )
    expression -> ( expression )

Затем на основе этой грамматики вы должны написать что-то, что анализирует токены выражений в деревья.

Таким образом, у вас может быть дерево, похожее на это (простите за искусство ASCII)

            +
          /   \
         5     *
              / \
             x   3

Где это представляет собой выражение 5 + (x * 3). Имея это в древовидной структуре, очень легко оценивать выражения в вашем коде: вы можете рекурсивно спускаться по дереву, выполняя операции с дочерними узлами в качестве аргументов.

См. следующие статьи Википедии:

Или обратитесь в местный отдел информатики. :-)

Существуют также инструменты, которые будут генерировать эти парсеры для вас на основе грамматики. Вы можете выполнить поиск по запросу «генератор парсеров».

person asveikau    schedule 10.12.2009

Не делайте динамическое выделение буфера явным образом с использованием вектора.
Это делает управление памятью неявным.

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

Лично я не использую close() явно (если только я не хочу поймать исключение). Просто откройте файл в области, которая заставит деструктор закрыть файл, когда он выйдет за пределы области.

person Martin York    schedule 10.12.2009
comment
buffer(lenght]); ‹-- У вас там прячется лишний ] :) - person Billy ONeal; 10.12.2009

Это может помочь:

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

Особенно раздел 7.3.

Возможно, вам будет лучше просто вводить строки, а не искать и использовать маршрут charbuffer.

person Stu    schedule 10.12.2009