Skip to content

Instantly share code, notes, and snippets.

@w495
Created April 29, 2014 00:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save w495/11388030 to your computer and use it in GitHub Desktop.
Save w495/11388030 to your computer and use it in GitHub Desktop.
token-vector-1
/**
* ----------------------------------------------------------------------------
* @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