Created
April 29, 2014 00:40
-
-
Save w495/11388030 to your computer and use it in GitHub Desktop.
token-vector-1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: token_type.h | |
* вынести в отдельные файлы | |
* ---------------------------------------------------------------------------- | |
**/ | |
#include<stdio.h> | |
#include<stdlib.h> | |
/** | |
* Создадим параметрические макросы с переменным числом аргументов. | |
* Они понадобятся для удобства отладки. | |
* | |
* @HINT_1: Что это такое (только для C99): | |
* http://en.wikipedia.org/wiki/Variadic_macro | |
* | |
* @HINT_2: Что за `033[` | |
* http://habrahabr.ru/post/119436/ | |
**/ | |
#define LOG_HELPER(fmt, ...) \ | |
fprintf( \ | |
stderr, \ | |
"\033[32mLOG:\033[0m " \ | |
"\033[33m%s\033[0m " \ | |
"\033[36m%s\033[0m " \ | |
"[\033[1m%d\033[0m] : " fmt "%s", \ | |
__FILE__, \ | |
__FUNCTION__, \ | |
__LINE__, \ | |
__VA_ARGS__ \ | |
) | |
#define LOG(...) LOG_HELPER(__VA_ARGS__, "\n") | |
/** | |
* @typedef Тип токена | |
* | |
* @HINT_1: Мы умышленно не даем имя перечислению, | |
* а только описываем его. Так выглядит компактнее. | |
* | |
* @HINT_2: enum --- по сути являются константами, | |
* для констант есть общая договоренность, | |
* писать их прописными буквами. | |
*/ | |
typedef enum { | |
VARIABLE, | |
NUMBER, | |
OPERATOR, | |
NEW | |
} token_type_t; | |
/** | |
* @typedef Знак токена. | |
*/ | |
typedef enum { | |
MINUS, | |
REST | |
} token_sign_t; | |
int is_variable(char in); | |
int is_number(char in); | |
int is_operator(char in); | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец token_type.h | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: token.h | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** @TODO: #include<stdio.h> */ | |
/** @TODO: #include<stdlib.h> */ | |
/** @TODO: #include "token_type.h" */ | |
/** | |
* @typedef Объявление токена | |
* | |
* | |
* @HINT_1: Мы умышленно не даем имя структуре, | |
* а только описываем ее.Так выглядит компактнее. | |
* | |
* @HINT_2: в Си есть договоренность добавлять `_t` для типов, | |
* которые созданы через `typedef`. | |
**/ | |
typedef struct { | |
token_type_t type; | |
token_sign_t sign; | |
int priority; | |
/* | |
* Как я понял, токен никогда | |
* не бывает одновременно `number`, `variable` и `operator`. | |
* Если это так, то эту троицу можно положить в `union`. | |
* Это сэкономит нам 2 байта на структуру. | |
* | |
* Думаю, Вы в курсе, но на всякий случай: | |
* http://www.tutorialspoint.com/cprogramming/c_unions.htm | |
* http://stackoverflow.com/questions/346536/difference-between-a-structure-and-a-union-in-c | |
* | |
*/ | |
int number; | |
char variable; | |
char operator; | |
} token_t; | |
/** | |
* @fn Возвращает пустой токен. | |
*/ | |
token_t* token_create(); | |
/** | |
* @fn Выводит токен на стандартный поток вывода (stdout). | |
*/ | |
void token_print(token_t token); | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец token.h | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: token_vector.h | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** @TODO: #include "token.h" */ | |
/** | |
* @typedef Вектор токенов | |
**/ | |
typedef struct { | |
/* | |
* Для размеров принято использовать `size_t`. | |
* Это псевдоним для `unsigned int` или `unsigned long int` | |
* (в зависимости от архитектуры) | |
*/ | |
size_t size; | |
/* | |
* В данном случае, можно использовать массив указателей. | |
* При этом измениться только `token_vector_add` и `token_vector_print`. | |
* Это будет гораздо эффективнее, потому что не будет | |
* копирования всей структур `token` при добавлении в массив. | |
* А так получается, вы делаете двойную работу: | |
* Выделяете память по token_create, а потом еще | |
* и при добавлении в вектор. | |
*/ | |
token_t *tokens; | |
} token_vector_t; | |
/** | |
* @fn Возвращает пустой вектор токенов. | |
*/ | |
token_vector_t * token_vector_create(); | |
/** | |
* @fn Создает вектор токенов, прочитанный из файла `input`. | |
*/ | |
token_vector_t * token_vector_read(FILE* input); | |
/** | |
* @fn Добавляет токен, к вектору токенов. | |
*/ | |
token_vector_t * token_vector_add(token_vector_t *, const token_t*); | |
/** | |
* @fn Выводит вектор токенов на `stdout`. | |
* | |
* @HINT_1: сама идея этой функции, несколько не логична; | |
* мы везде передаем указатели, а тут почему-то решили | |
* передавать значение; | |
* теоретически такое поведение может вызвать | |
* медленную работы программы. | |
*/ | |
void token_vector_print(token_vector_t); | |
/** | |
* @fn ??? | |
*/ | |
void polis_notation(token_vector_t*); | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец token_vector.h | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: main.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** @TODO: #include "token_vector.h" */ | |
int main() { | |
LOG(); | |
token_vector_t* vec = token_vector_read(stdin); | |
LOG(); | |
token_vector_print(*vec); | |
LOG(); | |
printf("\n"); | |
return 0; | |
} | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец main.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: token_vector.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** @TODO: #include "token_vector.h" */ | |
/** | |
* @fn Возвращает пустой вектор токенов. | |
* | |
* @HINT: Не нужно передавать указатель на указатель, | |
* а потом его разыменовывать. | |
* Можно просто указатель передать из самой функции. | |
*/ | |
token_vector_t* token_vector_create() { | |
LOG(); | |
token_vector_t *token_vector = NULL; | |
token_vector = malloc(sizeof(token_vector_t)); | |
token_vector->size = 0; | |
token_vector->tokens = malloc(sizeof(token_t)); | |
LOG("token_vector = %p", (void*) token_vector ); | |
return token_vector; | |
} | |
/** | |
* @fn Создает вектор токенов, прочитанный из файла `input`. | |
*/ | |
token_vector_t * token_vector_read(FILE* input) { | |
LOG(); | |
token_vector_t * token_vector = token_vector_create(); | |
LOG(); | |
int condition = 1; | |
int minus = 0; | |
LOG("token_vector = %p", (void*) token_vector ); | |
LOG("token_vector->size = %lu\n", token_vector->size); | |
for (;;) { | |
char in = getc(input); | |
LOG("in = '%c' (%d)", in, (int)in); | |
if (in == '\n') | |
return token_vector; | |
else if (condition && in == '-') { | |
condition = 0; | |
minus = 1; | |
continue; | |
} | |
else if (is_operator(in)) { | |
LOG("OPERATOR"); | |
token_t *token = token_create(); | |
token->type = OPERATOR; | |
token->operator= in; | |
if (in == '(') | |
token->priority = 0; | |
if (in == ')') | |
token->priority = 1; | |
if (in == '+' || in == '-') | |
token->priority = 2; | |
if (in == '/' || in == '*') | |
token->priority = 3; | |
condition = 1; | |
token_vector = token_vector_add(token_vector, token); | |
continue; | |
} | |
else if (is_number(in)) { | |
LOG("NUMBER"); | |
token_t *token = token_create(); | |
token->type = NUMBER; | |
token->number = in - '0'; | |
condition = 0; | |
if (minus) { | |
token->sign = 0; | |
minus = 0; | |
} | |
token_vector = token_vector_add(token_vector, token); | |
continue; | |
} | |
else if (is_variable(in)) { | |
LOG("VARIABLE"); | |
token_t *token = token_create(); | |
token->type = VARIABLE; | |
token->variable = in; | |
condition = 0; | |
if (minus) { | |
token->sign = 0; | |
minus = 0; | |
} | |
token_vector = token_vector_add(token_vector, token); | |
continue; | |
} | |
else { | |
LOG("ERRORS\n"); | |
return token_vector; | |
} | |
} | |
return token_vector; | |
} | |
/** | |
* @fn Добавляет токен, к вектору токенов. | |
*/ | |
token_vector_t* token_vector_add( | |
token_vector_t* token_vector, | |
const token_t* token | |
){ | |
LOG("token = %p", (void*) token); | |
token_vector->size++; | |
LOG("token_vector->size = %lu", token_vector->size); | |
LOG("token_vector->tokens = %p\n", (void*)(token_vector->tokens)); | |
token_vector->tokens = realloc( | |
token_vector->tokens, | |
token_vector->size * sizeof(token_t) | |
); | |
LOG("token_vector->tokens = %p\n", (void*)(token_vector->tokens)); | |
/* | |
* Вот тут творится крайне не эффективная вещь! | |
* Повторно выделяется память под token. | |
*/ | |
token_vector->tokens[token_vector->size - 1] = *token; | |
LOG(); | |
return token_vector; | |
} | |
/** | |
* @fn Выводит вектор токенов на `stdout`. | |
* Может быть, лучше token_vector_t* token_vector. | |
*/ | |
void token_vector_print(token_vector_t token_vector) { | |
for (int i = 0; i < token_vector.size; i++) { | |
token_print(token_vector.tokens[i]); | |
} | |
} | |
/** | |
* @fn ??? | |
*/ | |
void polis_notation(token_vector_t * token_vector) { | |
int i; | |
token_vector_t *vec = NULL; | |
token_vector_create(vec); | |
for (i = 0; i < token_vector->size; ++i) { | |
if ((token_vector->tokens + i)->type == 1 | |
|| (token_vector->tokens + i)->type == 0) { | |
LOG("!!!\n"); | |
} | |
} | |
} | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец token_vector.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: token.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** @TODO: #include "token.h" */ | |
/** | |
* @fn Возвращает пустой токен. | |
*/ | |
token_t* token_create() { | |
LOG(); | |
token_t *token = NULL; | |
token = malloc(sizeof(token_t)); | |
token->type = NEW; | |
token->sign = REST; | |
token->number = 0; | |
token->priority = 0; | |
token->variable = '\0'; | |
token->operator= '\0'; | |
LOG("ok, token = %p", (void*) token ); | |
return token; | |
} | |
/** | |
* @fn Выводит токен на стандартный поток вывода (stdout). | |
*/ | |
void token_print(token_t token) { | |
switch (token.type) { | |
case NEW: | |
return; | |
case NUMBER: | |
switch (token.sign) { | |
case MINUS: | |
printf("-"); | |
case REST: | |
break; | |
} | |
printf("%d", token.number); | |
return; | |
case VARIABLE: | |
switch (token.sign) { | |
case MINUS: | |
printf("-"); | |
case REST: | |
break; | |
} | |
printf("%c", token.variable); | |
return; | |
case OPERATOR: | |
printf("%c", token.operator); | |
return; | |
} | |
} | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец token.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: token_type.c | |
* ---------------------------------------------------------------------------- | |
**/ | |
/** @TODO: #include "token_type.h" */ | |
/** | |
* Проверки | |
*/ | |
int is_variable(char in) { | |
return ((in >= 'a' && in <= 'z') || (in >= 'A' && in <= 'Z')); | |
} | |
int is_number(char in) { | |
return (in >= '0' && in <= '9'); | |
} | |
int is_operator(char in) { | |
return (in == '-' || in == '+' || in == '/' || in == '*' || in == '(' | |
|| in == ')'); | |
} | |
/** | |
* ---------------------------------------------------------------------------- | |
* @TODO: конец token_type.c | |
* ---------------------------------------------------------------------------- | |
**/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment