05a-enumerate (1238880)
Текст из файла
ENUMERATEМинимум о перечисляемых типах и объединениях в языке CК. Владимиров, Intel, 2019mail-to: konstantin.vladimirov@gmail.comКонстанты времени исполнения•Модификатор const означает, что помеченная им переменная не можетизмениться во время выполнения программыconst int i = 5;i = 2; // ошибка•Но при этом её значение может быть получено очень поздноint a[20];fill(a);const int j = a[0];•Поэтому считается, что их значение неизвестно на этапе компиляции•Это имеет одно печальное последствиеКонстанты времени исполнения•Такие константы не могут быть использованы для размера массивовconst int asize = 5;int a[asize]; // ошибка•Дело в том, что размер массива должен быть известен на этапе компиляции•Если не рассматривать препроцессор, язык C имеет одну возможностьсделать константу времени компиляции: перечислимый типenum { asize = 5 };int a[asize]; // всё хорошо•Настало время поговорить о них подробнееПеречислимый тип•Главное предназначение enumerations: задавать синонимы для перечисленийenum weekday { monday, tuesday, wednesday, thursday,friday, saturday, sunday };enum state { Working, Failed, Freezed };enum year { Jan, Feb, Mar, Apr, May, Jun, Jul,Aug, Sep, Oct, Nov, Dec };•Перечисление определяет тип, который можно использовать в программеenum weekday w = monday;assert (w < sunday);Перечислимый тип•Все значения перечислимых типов – целые числа (как int)•По умолчанию они начинаются с нуляenum state { Working, Failed, Freezed };assert(Working == 0);enum state w = Failed;assert(w == 1);•Но можно указывать любые значенияenum state { Working = 6, Failed = 12, Freezed };assert(Freezed == 13); // не указанные значения растут как +1Неименованные перечислимые типы•Перечисляемый тип не задаёт область видимости, поэтому нельзядублировать перечислителиenum result { Ok = 0, Failed = -1};enum state { Working = 0, Failed, Freezed }; // ошибка•До некоторой степени каждый перечислимый тип это просто наборконстант.
Поэтому если не нужны объекты этого типа, его можно никак неназыватьenum { ASIZE = 10, BSIZE = 20 };int arr[ASIZE];int s = ASIZE - 1; // нормально, перечисление неименованноеИменованные перечислимые типы и int•Перевод из именованных перечислимых типов в int и обратно считаетсядурным тономenum state { Working = 6, Failed = 12, Freezed };int t = 4;enum state s = t; // можно, но сомнительно•Операции над именованными перечислимыми типами – тоже дурной тонenum state s = Working;s += 1; // можно, но ещё более сомнительно•Rule of thumb: именованные перечисления лучше всего только сравнивать наравенство и неравенство и оперировать только внутри их значенийПеречислимые типы и функции•Именованные перечислимые типы могут быть как аргументами, так ирезультатами функцийenum State { STATE_OK = 0, STATE_FAILED = -1 };enum State get_state();void set_state(enum State s);•Часто, это лучше, чем возвращать int, поскольку естественным образомдокументирует возвращаемые значения•Разумеется, и передавать и возвращать можно и по указателюvoid modify_state(enum State *s);Объединения•Одним из главных применений перечислимых типов являются объединения•Объединение очень похоже на структуру, только все поля в нём лежат поодному адресуstruct S {int x;char c;};union U {int x;char c;};xcxcОбъединения•Одним из главных применений перечислимых типов являются объединения•Разумеется, брать из объединения можно только то, что туда положилunion IntChar {int x;char c;};cxunion IntChar ic;ic.c = 'a';int y = ic.x; // крайне дурной тон (особенно в C++)•И здесь удобно использовать перечисленияОбъединения•Здесь показана структура с объединением и перечислениемenum DTS { DT_DAY = 0, DT_TIME };struct DT {enum DTS what;union DayOrTime {int day;time_t time;} u;}whatdaytimestruct DT d1 = { .what = DT_DAY, .u.day = 42 }; // C stylestruct DT d2 = { DT_DAY, 42 }; // C++ compatibleПример: лексический анализ•Нужно ввести скобочное выражение, содержащее четыре основных операции(2 + 3) * 5 - 7•Казалось бы это несложно, но есть проблемы•Пробелы могут быть введены лишние или не введены вообще(2+•3)*56 - 7Нужна диагностика для ошибок(2 + 3] * 56 - Z•Как представить считанное выражение?Идея: массив лексем•Лексема это операция, скобка или числоenum lexem_kind_t { OP, BRACE, NUM };enum operation_t { ADD, SUB, MUL, DIV };enum braces_t { LBRAC, RBRAC };struct lexem_t {enum lexem_kind_t kind;union {enum operation_t openum braces_t b;int num;} lex;};(2"(2+3)*56 – 7"+)3*56-7Problem LX•Напишите функцию, которая делает из строки массив лексемstruct lex_array_t {struct lexem_t *lexems;int size, capacity;};struct lex_array_t lex_string(const char *str) {// TODO: your code here}•Пробелы и пробельные символы ничего не значат•При ошибке разбора должно печататься сообщение и завершаться программаПример: синтаксические деревья•Выражению ((2 + 5) * 7 - 13 / 4) cоответствует дерево•Удобный тип для содержимого узла такого дерева-enum node_kind_t { NODE_OP, NODE_VAL};struct node_data_t {enum node_kind_t k;union {enum operation_t op;int d;} u;};•*+2/75Очевидно ли вам как, имея построенное дерево, вычислить выражение?134Пример: синтаксические деревья•Выражению ((2 + 5) * 7 - 13 / 4) cоответствует дерево•Удобный тип для узла такого дерева-struct node_t {struct node_t *left, *right;struct node_data_t data;};•Вычисление это просто postorder обход:•сначала вычисляется левое поддерево•потом правое•потом применяется сама операция*+2/75134Обсуждение•Как перейти от массива лексем к синтаксическому дереву?Синтаксический разбор•Процесс построения синтаксического дерева из лексем называетсясинтаксическим разбором (parsing)•Он зависит от грамматики.
Например для простейших выраженийexpr ::= mult {+, -} expr | multmult ::= term {*, /} mult | termterm ::= ( expr ) | number•Здесь терминальные символы operation, number и скобки соответствуюттипам лексем в массиве•Каждый нетерминал (курсивом) соответствует рекурсивному вызову функцииПример разбораexprmult – expr-term * term – mult( expr ) * 56 – term*7( mult + expr ) * 56 – 7+( term + mult ) * 56 – 756( 2 + term ) * 56 – 7( 2 + 3 ) * 56 - 723Problem ST – синтаксическое дерево•На вход приходят выражения, содержащие числа и арифметическиеоперации2 + 2 * (3 – 4) / 6•Все операции имеют обычный приоритет и вычисляются слева направо2 + 2 * 3 → 8(2 + 2) * 3 / 5 * 2 → 12 / 5 * 2 → 2 * 2 → 463 + 86 / 3 / 5 * ( 13 - 69 ) → 53 + 5 * ( 13 - 69 ) → -217•Необходимо выдать на выход значение для каждого из выражений•Используйте лексический анализ из проблемы LX.
Характеристики
Тип файла PDF
PDF-формат наиболее широко используется для просмотра любого типа файлов на любом устройстве. В него можно сохранить документ, таблицы, презентацию, текст, чертежи, вычисления, графики и всё остальное, что можно показать на экране любого устройства. Именно его лучше всего использовать для печати.
Например, если Вам нужно распечатать чертёж из автокада, Вы сохраните чертёж на флешку, но будет ли автокад в пункте печати? А если будет, то нужная версия с нужными библиотеками? Именно для этого и нужен формат PDF - в нём точно будет показано верно вне зависимости от того, в какой программе создали PDF-файл и есть ли нужная программа для его просмотра.