Столкновение типа варианта

Дополнительный вопрос

Итак, я играл с

Boost Mini C Учебное пособие

Я добавил правило для разбора строковых литералов. Цель состоит в том, чтобы я мог анализировать и компилировать такие программы, как (функциональность уже встроена):

int ret(int x) {
    return x;
}

int main() {
   int x = 5;
   return ret(x)*2;
}

А также (хочу добавить эту функциональность),

string print(string s) {
   return s;
}

int main() {
   string foo = "bar";
   print(foo);
   return 0;
}

Независимо от того, скомпилированы ли последние два примера, скажем, с gcc, несущественно.

Итак, суть того, что я добавил, заключается в следующем:

В файле expression_def.hpp (добавлено производственное правило quoted_string):

quoted_string = '"' >> *('\\' >> char_ | ~char_('"')) >> '"'; // ADDED THIS

            primary_expr =
            uint_ 
            |   quoted_string // ADDED THIS
            |   function_call
            |   identifier
            |   bool_
            |   '(' > expr > ')'
            ;

в ast.hpp добавлен вариантный тип 'std:string':

typedef boost::variant<
            nil
            , bool
            , unsigned int
            , std::string // ADDED THIS
            , identifier
            , boost::recursive_wrapper<unary>
            , boost::recursive_wrapper<function_call>
            , boost::recursive_wrapper<expression>
        >
        operand;

Вот объявление правила для добавления, а также правило, с которым оно сталкивается:

qi::rule<Iterator, std::string(), skipper<Iterator> > identifier;
qi::rule<Iterator, std::string()> quoted_string; // declaring this without the skipper 
                             // lets us avoid the lexeme[] incantation (thanks @sehe).

Проблема сейчас в том, что компилятор путает то, что должно быть "идентификатором" для "quoted_string" - или фактически просто std::string.

Я предполагаю, что причиной проблемы является тот факт, что они оба имеют возвращаемый тип подписи std:: string, но я не знаю хорошего обходного пути здесь. Кроме того, структура 'identifier' имеет член данных типа std:: string, с которым она инициализируется, поэтому на самом деле компилятор не может определить между ними, а вариант std:: string в итоге оказывается лучшим соответствием.

Теперь, если я изменю std:: string на char*, вот так:

typedef boost::variant<
                nil
                , bool
                , unsigned int
                , char* // CHANGED, YET AGAIN
                , identifier
                , boost::recursive_wrapper<unary>
                , boost::recursive_wrapper<function_call>
                , boost::recursive_wrapper<expression>
            >
            operand;

он будет компилироваться и работать с целыми числами, поспорим, что я не смогу проанализировать строки (фактически VS вызовет abort()). Следует отметить, что, поскольку каждый вариант нуждается в перегрузке, в моем коде есть что-то вроде:

bool compiler::operator()(std::string const& x)
    {
        BOOST_ASSERT(current != 0);
        current->op(op_string, x);
        return true;
    }

а также

 void function::op(int a, std::string const& b)
        {
            code.push_back(a);
            code.push_back(b.size());
            for (uintptr_t ch : b)
            {
                code.push_back(ch);
            }
            size_ += 2 + b.size();
        }

Они оба работают без сбоев, когда мне нужно разобрать строки (конечно, жертвуя способностью обрабатывать целые числа).

Их целочисленные эквиваленты (и находятся в compiler.cpp)

bool compiler::operator()(unsigned int x)
        {
            BOOST_ASSERT(current != 0);
            current->op(op_int, x);
            return true;
        }

и конечно:

  void function::op(int a, int b)
        {
            code.push_back(a);
            code.push_back(b);
            size_ += 2;
        }

Если мне нужно изменить тип варианта с std:: string на char*, тогда мне придется обновить перегрузки, и из-за наследства языка C он выглядит немного некрасиво.

Я понимаю, что это может быть немного утомительно и не очень привлекательно, чтобы прочесывать источник, но я уверяю вас, что это действительно не так. Этот урок по компиляции просто помещает байт-код в вектор, который по своей конструкции обрабатывает только целые числа. Я пытаюсь изменить его, чтобы обрабатывать строки, а также, следовательно, дополнения и перегрузки, а также необходимость unintptr_t. Любой, кто знаком с материалом и / или Boost, вероятно, точно знает, на что он смотрит (ehem, @sehe, ehem!).

0 ответов

Другие вопросы по тегам