Форум программистов, компьютерный форум CyberForum.ru

Пишем свой интерпретатор языка BASIC - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ Меню и список http://www.cyberforum.ru/cpp-beginners/thread41194.html
Здравствуйте форумчане. Помоги пожалуйста в следующем вопросе: У меня есть 2связный список, написано меню. Но в моменте когда написано make a list и delete custom необходимо чтобы выводились: Введите элемент и номер. вот сам код: #ifndef __list_h #define __list_h #include <iostream>
C++ Здравствуйте! Не могу поместить class в один файл с программой. file.hpp #include "Cat.hpp" // здесь классы "2)" Cat::Cat(int initialAge) { itsAge = initialAge; } Cat::~Cat() { http://www.cyberforum.ru/cpp-beginners/thread41186.html
Массивы строк C++
Привет всем! Задан массив строк. Как узнать который символ встечаетса найбольшое количество раз в етом массиве?
C++ вывод на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер
Please, help me!!! Вот текст программы, которая выводит на экран набор треугольников и квадратов, которые произвольно двигаются и меняют размер только квадратов. Проблема в том, что необходимо исправить код, чтоб фигуры не исчезали за экран (т.е. 640х460) и были компактным набором, т.е. двигались неменяя своего положения относительно друг друга и стукаясь об стенку экрана меняли свое...
C++ Округление дробного числа до целого в большую сторону. http://www.cyberforum.ru/cpp-beginners/thread41139.html
Доброго дня. Я новичок в программирование на Visual C++. Проблема такая программа должна считать кол-во месяцев, если числа целые то программа шла дальше, если дробное то (например 3.33333) программа не округляет это число (в большую сторону) до 4. Перелопатил тонны литературы, но пропустил или не нашёл этого, большая просьба написать функцию которая могла бы это делать, или способ какой.
C++ Код из Delphi в C++ Нужно написать курсовую на C++. Сам я в программировании плохо шарю (не программист). Попросил у народу помощи, помогли. Но решение на Delphi: {$APPTYPE CONSOLE} type byteset=set of byte; var d:array of longint; procedure c; var a,b,i:longint; подробнее

Показать сообщение отдельно
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16828 / 5249 / 321
Регистрация: 30.03.2009
Сообщений: 14,136
Записей в блоге: 26
30.06.2009, 12:23     Пишем свой интерпретатор языка BASIC
Точка не должна отлавливаться. У тебя "10.0" должно идти как единая грамматическая единица (token). Собственно, потому я и предложил навести порядок, что логически у тебя некорректно написано.

Сейчас у тебя get_token выдирает число по одной циферке. Это не есть правильно. get_token за раз должен выдрать целиком грамматическую единицу. Т.е. если записано "123", то за раз будет выдрано "123", если "123.45", то "123.45". А вот если "123.45.67", то первая лексическая единица будет "123.45", а следующая "." (или ".67", если понимать дополнительный вариант записи плавающих чисел). Если это ключевое слово "print", то и будет "print" (с чем у тебя на текущий момент проблемы). Сейчас у меня под рукой нет формальных описаний, но если желаешь - ознакомлю тебя с формальными описаниями грамматики и лексики

Добавлено через 1 минуту 40 секунд
> Я уже успел поискать про машинную запись чисел с плавающей точкой,я так
> понимаю,этот ньюанс требует пересмотра посимвольного разбора с помощью
> putback?

Нет. Как я уже писал, get_token за раз должен выдрать "123.45", котору затем стандартными функциями ты превратишь в плавающее число. Возможно, я пока объясняю слишком непонятно, но если ты морально готов к перелопачиванию своей программы, могу начать пояснять более подробно.

Добавлено через 5 минут 0 секунд
Хотя нашёл в инете пример формального описания грамматики. Так что если надо - могу вкратце пояснить суть работы грамматического анализатора

Добавлено через 2 часа 51 минуту 6 секунд
================================================================

В общем, появилось немного свободного времени на работе. Так что родил примерно следующее пояснение

Есть две вещи разного уровня: грамматика и лексика. Грамматика - это по сути дела правила построения слов из отдельных букв. Лексика - построение предложений из слов (а последние построены по правилам грамматики)

Давай рассмотрим простейший вариант того, какие грамматические единицы (token'ы) должны поддерживаться нашим интерпретатором:
  • константы (числа): целочисленные и плавающие
  • идентификаторы (имена переменных)
  • ключевые слова: в нашем случае пока только PRINT, но для простоты в будущем развитии я бы ввёл ещё LET
  • знаки операций, которые принято называть разделителями (delimiter) : + - * / | & ~ =
  • признак конца строки (поскольку конец строки будет являться разделителем между предложениями)
  • признак конца файла

Задача парсера, который по сути дела является грамматическим анализатором, является нарезка входного текста на слова (token'ы). При этом грамматический анализатор будет пропускать комментарии, ненужные пробелы и знаки табуляции. Мы будем считать, что один вызов GetToken (я всё-таки обзову именно так, чтобы не путать с тем, что сейчас есть у тебя) вынимает из входного потока одно слово (token). Как это будет представлено на уровне данных, пока не рассматриваем (чисто чтобы теорию понять)

Вот для такого примера:

Код
let a = 5.123 # комментарий
print a
последовательные вызовы GetToken должны вернуть следующий набор значений:
  • Ключевое слово (keyword) LET
  • Идентификатор (identifier) A
  • Операция (delimiter) =
  • Плавающая константа (float constant) 5.123
  • EOL (конец строки)
  • Ключевое слово PRINT
  • Идентификатор A
  • EOL (конец строки)
  • EOF (конец файла)

При этом комментарии за пределы парсера вообще не вылезают. Дабы остальным компонентам с ними не возиться

Теперь, как это всё должно выглядеть технически. По результату вызова GetToken фактически должен возвращать в качестве результата некие два значения. Первым значением является непосредственное строковое представление слова, которое полезно для печати диагностики, отладки, а так же необходимо для разбора идентификаторов и констант. Т.е. для нашего примера этими строковыми значениями будут "LET", "A", "=", "5.123" и т.д. Вторым значением является значение некоего enum'а, которое удобно обрабатывать в виде целочисленного значения и которое является описанием того, что у нас записано в строке. Таким образом пара этих значений полностью описывает наш token

Как конкретно сделать enum - зависит от того, как тебе удобно работать.
Я бы сделал так:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
enum parser_TokenType
{
  TOKEN_NULL = 0,
 
  TOKEN_CONST_INT,   // целочисленная константа
  TOKEN_CONST_FLOAT, // плавающая константа
 
  TOKEN_IDENT,       // идентификатор
 
  TOKEN_KW_LET,      // ключевое слово LET
  TOKEN_KW_PRINT,    // ключевое слово PRINT
 
  TOKEN_DELIM_EQUAL, // знак "="
  TOKEN_DELIM_PLUS,  // знак "+"
  TOKEN_DELIM_MINUS, // знак "-"
  ....
 
  TOKEN_EOL,         // конец строки
  TOKEN_EOF,         // конец файла
 
  TOKEN_LAST
};
При этом для значений TOKEN_CONST_INT, TOKEN_CONST_FLOAT и TOKEN_IDENT нам необходимо второе значение (которое описывает строковое представление token'а), а в остальных случаях элемент enum'а полностью описывает наш token

В итоге интерфейс нашего грамматического анализатора будет примерно таким:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* Инициализация парсера. В качестве file_name подаём имя файла,
 * с которым работаем. В случае проблем с открытием файла возвращаем
 * false, если всё в порядке - true */
extern bool parser_Init (const char *file_name);
 
/* Процедура parser_GetToken вынимает очередное слово из нашего входного
 * потока. Порезультату работы записываются переменные parser_CurToken
 * и parser_LastTokenStr. Процедура parser_GetToken возвращает то же значение,
 * что записывается в parser_CurToken (для удобства работы).
 * В перменные parser_CurFile, parser_CurLine записывается информация
 * о положении в файле текущего token'а (для выдачи ошибок) */
extern parser_TokenType parser_GetToken (void);
extern parser_TokenType parser_CurToken;
extern char *parser_CurTokenStr;
extern char *parser_CurFile;
extern unsigned parser_CurLine;
 
/* Отладочная печать текущего token'а */
extern void parser_PrintCurToken (void);
 
/* Завершение работы */
extern void parser_Finish (void);
Попробуй наваять парсер (который по сути является грамматическим анализатором) примерно по такому интерфейсу. Либо меняй его на своё усмотрение, лишь бы остался принцип того, что на один вызов GetToken вытаскивается грамматическая единица целиком. И заодно встрой в программу под макросом или опцией отладочную печать из-под своего парсера. Тут тоже можешь экспериментировать. Печать может быть интегрирована прямо вовнутрь GetToken'а, можно её вызывать снаружи. Лишь бы тебе было удобно по печатям отслеживать процесс работы

Ну и весь грамматический анализатор полезно выделить в отдельный файл

Добавлено через 14 минут 34 секунды
Вот примерное формальное описание грамматики:

Код
Const = ConstInt | ConstFloat
ConstInt = Digit { Digit }
ConstFloat = Digit { Digit } "." Digit { Digit }
Ident = Letter { Letter | Digit }
Letter = "A" | "B" | ... | "y" | "z"
Digit = "0" | "1" | ... | "9"
KeywordLet = "LET"
KeywordPRINT = "PRINT"
То, что написано с заглавной буквы, представляет собой правило. То, что в кавычках - непосредственно указанные внутри кавычек символ(ы). Символ | означает один из вариантов, то, что заключено в фигурные скобки - это ноль или более потворений того, что заключено в них (скобках)

Твой анализатор должен делать разбор, руководствуясь этими формальными правилами (глядя на них проще понмать, что в каком порядке должно разбираться). Исходя из этих правил, например, "12.ab" должно трактоваться как ошибка, потому как ни в одно правило такая конструкция не вписывается. Пробелы и знаки табуляции означают конец текущего слова. При этом получается, что "12. " опять-таки не вписывается, т.к. после десятичной точки мы требуем хотя бы одну цифру (хотя можем этого и не делать)

Самая первая задача - научиться нарезать на слова в случае, когда нет грамматических ошибок. А уже потом пытаться отсекать ошибочные случаи
 
Текущее время: 07:39. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru