Что означает «контекстная строка для данного токена»?

#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:

Подумайте о контекстной строке, как вы видите в сообщениях об ошибках компилятора. Строка контекста используется для отображения того, что окружает токен или его контекст. Проблема в том, чтобы попросить что-то в трех строках:

  1. Строка текста, которая сразу же продолжает строку с токеном в ней.
  2. Строка текста, содержащая токен it.
  3. Строка с 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 ; }