#c #tokenize
#c #маркировать
Вопрос:
Я пишу назначение токенизатора (на c ) на основе курса nand2tetris, и для части назначения требуется контекстная строка. Я не уверен, что под этим подразумевается, и я ищу разбивку или какой-то псевдо / пример кода, чтобы проиллюстрировать, что это значит. (Я чувствую, что это тот случай, когда вы смотрите на полку в поисках книги, которая находится прямо перед вами, но вы не видите, потому что искали так долго!)
Инструкции:
Создайте контекстную строку для данного токена. Он показывает строку перед токеном, строку, содержащую токен, и строку с ^, обозначающую позицию токена. Табуляция останавливается каждые 8 символов в контекстной строке, табуляции заменяются пробелами (от 1 до 8), так что следующий символ начинается с 8-символьной границы.
Я знаю, что это, вероятно, случай очевидного английского, а не кода, но я просто немного потерялся, и любая помощь была бы легендарной, поскольку я все еще очень прост в программировании.
Я думал о чем-то вроде:
string token_context(Token token)
{
return "previous line n" "token" "somehow having 8 spaces and the ^ symbol where the token is" ;
}
Комментарии:
1. возможно, вам будет полезно ознакомиться с использованием strtok(), старой функции c для токенизации токенов из строки в стиле C. См., например, geeksforgeeks.org/strtok-strtok_r-functions-c-examples и en.cppreference.com/w/cpp/string/byte/strtok . Пожалуйста, обратите внимание, что strtok поддерживает внутреннее состояние при вызове в цикле. Я действительно не уверен, что запрашивает задание, но оно может иметь что-то похожее на эту функцию?
2. Спасибо, я изучал это, но, по-видимому, strtok здесь не используется, поскольку мы должны читать вводимый символ за символом, а не как строку, поэтому, насколько я понимаю, разделителей нет.
Ответ №1:
Подумайте о контекстной строке, как вы видите в сообщениях об ошибках компилятора. Строка контекста используется для отображения того, что окружает токен или его контекст. Проблема в том, чтобы попросить что-то в трех строках:
- Строка текста, которая сразу же продолжает строку с токеном в ней.
- Строка текста, содержащая токен it.
- Строка с a
^
в ней. Размещение^
должно быть под фактическим токеном.
Материал о вкладках должен помочь вам получить ^
в нужном месте. По сути, это означает, что табуляция действует как переменное количество пробелов. Количество пробелов, с которыми работает табуляция, делает следующий символ кратным 8. Например "abtc"
, следует рассматривать как то же "ab c"
самое, что и потому, что символ табуляции ( t
) находился в третьем пробеле, и поэтому он действовал как 6 пробелов, так что символ c
будет находиться в восьмой позиции строки.
Комментарии:
1. Спасибо за разборку, Джонатан, я думаю, я понимаю, что означает задача (особенно в отношении табуляции и интервалов — большое спасибо за эту часть!), Но мне все еще неясно, как это будет выглядеть на практике / с точки зрения кода.
2. @DNM: У вас есть определение класса для токена, которое вы могли бы опубликовать?
3. @Gardener определения классов, которые у меня есть, состоят из двух частей:
4. #включить «tokeniser.h» #включить <iostream> с использованием std пространства имен; с использованием namespace Assignment_Tokeniser ; // эта основная программа помечает стандартный ввод и // печатает токены по мере их нахождения в main(int argc,char **argv) { Token token ; int count = 0 ; //запоминайте и отображайте каждый токен по мере его чтения token = next_token() ; while ( token_kind(token) != tk_eoi ) { cout << token_to_string(token) << endl ; token = next_token() ; count ; } cout << «чтение» << количество << » токенов» << endl ; возвращает 0; }
Ответ №2:
Пожалуйста, скомпилируйте и запустите этот код. Я думаю, это продемонстрирует использование табуляции и пробелов, как объяснил @Jonathan Geisler.
Пожалуйста, обратите внимание, что в системе вашего профессора предполагается, что табуляции занимают 8 пробелов. Однако в моей системе они выводят ширину пробела 4. Итак, у меня есть константа, определенная как tab_spaces, равная 8. Если вы обнаружите, что карат находится не в нужном месте, измените эту константу на 4 и повторите попытку.
Изучите выходные данные в вашем отладчике, и я думаю, это будет понятно.
Output:
int index = 10;
if(index < 8 amp; index % 2 == 1) {
^
Процесс завершен с кодом выхода 0
код:
#include <iostream>
#include <string>
using namespace std;
struct Token {
string prior_line;
string token_line;
string token;
size_t token_offset;
size_t token_length;
};
const size_t tab_spacing{8}; // this has to be '4' on my system
string token_context(Token token)
{
size_t tab_count = 0;
size_t space_count = 0;
string return_string{token.prior_line}; // 1st line: prior line
return_string = "n"; // end of line 1,
return_string = token.token_line; // 2nd line, the one with the token
return_string = "n"; // end of line 2,
// calculate tabs and spaces for line 3
tab_count = token.token_offset / tab_spacing; // tabs to get to token offset
space_count = token.token_offset % tab_spacing; // spaces to get to token offset
// Build the 3rd line of the context string by inserting tabs
for(size_t i = 0; i < tab_count; i ) {
return_string = "t";
}
// now insert the spaces
for(size_t i = 0; i < space_count; i ) {
return_string = " ";
}
// now, add the carat '^'
return_string = "^";
return_string = "n";
return return_string;
}
int main()
{
string str1 = "int index = 10;";
string str2 = "if(index < 8 amp; index % 2 == 1) {";
size_t token_offset = 13;
size_t token_length = 1;
string token_str = "amp;";
Token token;
token.prior_line = str1;
token.token_line = str2;
token.token_offset = token_offset;
token.token = token_str;
token.token_length = token_length;
std::cout << token_context(token) << std::endl;
return 0;
}
Комментарии:
1. Ах! Просто увидел ваш комментарий и начал добавлять определения классов, которые у нас есть. Я посмотрю и посмотрю на предоставленный код и посмотрю, как я могу его настроить. Спасибо за кодовую версию объяснения 🙂 Я добавил классы ниже, если вам было интересно (извините, это в случайных частях, слишком много символов, но ниже приведен один класс, а выше — один класс :))
2. использование std пространства имен; использование присваивания_токенизатора пространства имен; // token_is_in test аннулирует token_is_in_test(Token token,TokenKind kind) { cout << «token_is_in(token, << token_kind_to_string(kind) << «) возвращает » ; cout << (token_is_in(token,kind) ? «true»: «false») ; cout << endl; }
3. // эта основная программа маркирует стандартный ввод и // печатает токены по мере их нахождения в main(int argc,char **argv) { Token token ; int count = 0 ; // запоминает и отображает каждый токен по мере его чтения token = next_token() ; в то время как ( token_kind(token)!= tk_eoi ) { // выводить контекст каждые 4 токена
4. if ( count % 4 == 0 ) { cout << token_context(токен) << endl ; token_is_in_test(токен, tk_identifier) ; token_is_in_test(токен, tk_integer) ; token_is_in_test(токен, tk_double) ; token_is_in_test(токен, tk_keyword) ; token_is_in_test(токен, tk_keyword) токен,tk_symbol) ; }
5. cout << token_to_string(token) << endl ; token = next_token() ; } cout << «чтение» << количество << «токены» << endl ; возвращает 0 ; }