/*
BinTable.cpp
Было бы времени вагон, я бы м.б. использовал стек и не громоздил столько всего...
Оптимизировать не успеваю по той же причине, так что сильно не бейте.
© ---fg
*/
#include <stdio.h>
#include <string.h>
#include <conio.h>
//! .Const
// Приоритеты операций: "!", "/", "стрелка Пирса", "->", "<-", "/\", "\/", "+", "=>", "<=", " ~ ".
// Определения бинарных операций
# define _cnst0(a) 0 // 1. const 0
# define _cnst1(a) 1 // 2. const 1
# define _binnot(a) (!(a)) // 3. не a
# define _conunc(x,y) ((x)&&(y)) // 4. x и y
# define _disunc(x,y) ((x)||(y)) // 5. x или y
# define _binsum(x,y) ((x)!=(y)) // 6. x исключающее или y
# define _binnoy(x,y) ((x)&&!(y)) // 7. запрет y (x<-y)
# define _binnox(x,y) (!(x)&&(y)) // 8. запрет x (x->y)
# define _pirsar(x,y) (!((x)&&!(y)) // 9. стрелка Пирса
# define _bequal(x,y) ((x)==(y)) // 10. x эквивалентно y
# define _ximply(x,y) (!(x)||(y)) // 11. x импликация y (x=>y)
# define _yimplx(x,y) (!(y)||(x)) // 12. y импликация x (y=>x)
# define _shefsl(x,y) (!((x)&&(y))) // 13. штрих Шеффера
//
# define _blng(a,b,c) ((a)>=(b)&&(a)<=(c)) // Принадлежит ли a отрезку [b,c]
# define _B_CNT 16 // Число наборов (= 2^(число переменных) )
# define _B_OP_CNT 11 // Число видов операций (константа 11)
// Режимы парсинга строки
enum
{TEXT,OPSYMB,PRECOMMENT,COMMENT,EXIT};
//! .Types
// двоичное = {0,1}
typedef
char bin;
// символ операции
typedef
char opSmb;
// Предвычислительная хранящая структура
struct
{
opSmb opercode[5]; // Знак типа операции
char operand1; // Значение аргумента 1
char operand2; // Значение аргумента 2
} _keep[50];
// Таблица готовых значений
struct
{
char head[50+2][11]; // Заголовок колонки: заголовок [номер колонки] = "строка"
char cplc[50+2]; // Размер аголовка колонки
bin value[50][_B_CNT]; // Двоичное значение: значение [номер колонки][номер строки] = 0 или 1
} _table;
//! .Globals
// Bin variables
bin _x[_B_CNT],
_y[_B_CNT],
_z[_B_CNT],
_p[_B_CNT];
// Operation type format literas
opSmb _opcode[_B_OP_CNT][6]; // Максимум 5 символов в обозначении операции (+ '\0')
// Operation index
int _opcount=0;
// Function string
char _function[200];
//! .Code
//! Removes all symbols of type from string, pushing string left
void StrRemChar(char * string,const char toDel)
{
const int len=strlen(string);
char ch;
int i=0,j=0;
while(i<len)
{
ch=*(string+i);
if(ch==toDel)
{
j=i+1;
while(*(string+j)==toDel && j<len) j++;
*(string+i)=*(string+j);
*(string+j)=toDel;
}
i++;
}
*(string+i)='\0';
}
//! Неиспользуемая функция
//! Вставляет n символов = typ, начиная с установленной позиции pos со сдвигом строки str вправо
/*void StrPush(char * string,const char typ,const unsigned pos,unsigned n)
{
int i=strlen(string);
while(pos-1<=i) *(string+i+n)=*(string+i--);
i=pos-1;
while(n-->0) *(string+i++)=typ;
}
*/
//! Распознает массив значений переменной (либо операции под определенным номером), соотв. входному символу
bin * Recognize(const char operand)
{
bin * result=NULL;
switch(operand)
{
case 'x': result=_x; break;
case 'y': result=_y; break;
case 'z': result=_z; break;
case 'p': result=_p; break;
default :
// 0-значение зарезервировано и используется как указывающее на унарную операцию
if( _blng(operand,1,99)) result=_table.value[operand];
}
return result;
}
//! Возвращает результат бинарной операции соотв. входному индексу по старшинству операций
bin BinOperator(const char operation,const bin x,const bin y)
{
bin result;
switch(operation)
{
case 0 : result=_binnot(x); break;
case 1 : result=_shefsl(x,y); break;
case 2 : result=_pirsar(x,y); break;
case 3 : result=_binnox(x,y); break;
case 4 : result=_binnoy(x,y); break;
case 5 : result=_conunc(x,y); break;
case 6 : result=_disunc(x,y); break;
case 7 : result=_binsum(x,y); break;
case 8 : result=_ximply(x,y); break;
case 9 : result=_yimplx(x,y); break;
case 10: result=_bequal(x,y); break;
default: result=0; break;
}
return result;
}
//! Инициализиует наборы (xyzp), считывает и запоминает обозначения операций
int InitBin(const char *op_def_path)
{
// Инициализация наборов
int i=0;
while(_B_CNT>i)
{
_x[i]=(i>7);
_y[i]=(i%8>3);
_z[i]=(i%4>1);
_p[i]=(i%2);
i++;
}
// Определение символов операций
FILE *stream=NULL;
if((stream=fopen(op_def_path,"r"))!=NULL)
{
char ch,j,f=TEXT;
i=j=0;
while(fscanf(stream,"%c",&ch)==1 && i<_B_OP_CNT)
{
switch(f)
{
case TEXT:
if(ch=='{') f=OPSYMB;
else
if(ch=='/') f=PRECOMMENT;
break;
case OPSYMB:
if(ch=='}')
{
_opcode[i++][j]='\0';
j=0;
f=TEXT;
}
else
if(ch!='\n'&&ch!=' ') _opcode[i][j++]=ch;
break;
case PRECOMMENT:
if(ch=='/') f=COMMENT; else f=TEXT;
break;
case COMMENT:
if(ch=='\n') f=TEXT;
break;
}
}
fclose(stream);
i=1;
}
else
{
perror("Не могу открыть файл с определениями \nопераций (Data\\OpDef.txt)");
i=0;
}
return i;
}
//! Последовательно преобразует строу функции, вычленяя отдельные операции
int ParseBin(const char *func_def_path)
{
int i=0;
FILE *stream=NULL;
if((stream=fopen(func_def_path,"r"))!=NULL)
{
char *p,ch,size,k,j,f=TEXT;
bin *b;
// Считываем функцию из файла в строку
while(fscanf(stream,"%c",&ch)==1 && f!=EXIT)
{
switch(f)
{
case TEXT:
if(ch=='{') f=OPSYMB;
else
if(ch=='/') f=PRECOMMENT;
break;
case OPSYMB:
if(ch=='}')
{
_function[i++]='\0';
f=EXIT;
}
else
if(ch!='\n'&&ch!=' ') _function[i++]=ch;
break;
case PRECOMMENT:
if(ch=='/') f=COMMENT; else f=TEXT;
break;
case COMMENT:
if(ch=='\n') f=TEXT;
break;
}
}
fclose(stream);
//! place here text, displaying in dialog window
printf("Функция: %s\n",_function);
// Парсинг, связь операций
// Для унарных операций
size=strlen(_opcode[0]);
while((p=strstr(_function,_opcode[0]))!=NULL)
{
// Сохраняем в структуру
_opcount++;
_keep[_opcount].operand1=*(p+size);
_keep[_opcount].operand2=0;
strcpy(_keep[_opcount].opercode,_opcode[0]);
// Преобразуем строку
if(_opcount<10)
{
*(p+size)=_opcount+'0';
j=1;
}
else
{
*(p+size)=_opcount%10+'0';
*(p+size-1)=_opcount/10+'0';
j=2;
}
while(size-j>=0) *(p+size-j++)=' ';
// Сжимаем строку
StrRemChar(_function,' ');
}
// Для бинарных операций (: xBy )
i=1;
while(i<_B_OP_CNT)
{
size=strlen(_opcode[i]);
j=size+2;
f=1;
while((p=strstr(_function,_opcode[i]))!=NULL)
{
// Сохраняем в структуру
_opcount++;
// Парсим аргумент у
if(_blng( *(p+size),'0','9' ))
{
// Аргумент = индекс операции
_keep[_opcount].operand2=*(p+size)-'0';
if(_blng( *(p+size+1),'0','9' ))
{
// Индекс > 9
_keep[_opcount].operand2 = _keep[_opcount].operand2 * 10 + *(p+size+1)-'0';
j++;
}
}
else
{
// Аргумент = переменная
_keep[_opcount].operand2=*(p+size);
}
// Парсим аргумент х
if(!(_blng( *(p-1),'0','9' )))
{
// Аргумент = переменная
_keep[_opcount].operand1=*(p-1);
}
else
{
// Аргумент = индекс операции
_keep[_opcount].operand1=*(p-1)-'0';
if(_blng( *(p-2),'0','9' ))
{
// Индекс > 9
_keep[_opcount].operand1 = _keep[_opcount].operand1 + *(p-2)*10 -'0';
j++;
f++;
}
}
strcpy(_keep[_opcount].opercode,_opcode[i]);
// Преобразуем строку
k=0;
while(k<j) *(p-f+k++)=' ';
if(_opcount<10) *(p+size)=_opcount+'0';
else
{
*(p+size)=_opcount%10+'0';
*(p+size-1)=_opcount/10+'0';
}
// Сжимаем строку
StrRemChar(_function,' ');
}
i++;
}
// Закрываем сессию на всякий пожарный
_keep[_opcount+1].opercode[0]='0';
_keep[_opcount+1].opercode[1]='\0';
i=1;
}
else perror("Не могу открыть файл с определением \nфункции (Data\\FuncDef.txt)");
return i;
}
//! Вычисляет и пишет во внешний файл двоичную таблицу
int DrawBinTable(const char *bin_tab_path)
{
int i=0;
FILE *stream=NULL;
if((stream=fopen(bin_tab_path,"w"))!=NULL)
{
char j,opind,opnd1,opnd2, *str;
bin *x, *y; //указатели на массивы значений аргументов
// Вычисляем и сохраняем двоичные значения
i=1; // 0-значение зарезервировано и используется как указывающее на унарную операцию
while(i<=_opcount)
{
// Ищем индекс операции по массиву
opind=0;
str=_keep[i].opercode;
opnd1=_keep[i].operand1;
opnd2=_keep[i].operand2;
while(strcmp(_opcode[opind],str)) opind++;
// Высчитываем бинарные значения для операций
j=0;
x=Recognize(opnd1);
y=Recognize(opnd2);
while(j<_B_CNT)
{
_table.value[i][j]=BinOperator(opind,*(x+j),*(y+j));
j++;
}
// Стряпаем заголовки
if(opnd2==0)
{
opnd2=opnd1;
opnd1=0;
}
str=_table.head[i];
if(_blng(opnd1,10,99))
{
*str=opnd1/10+'0';
*(str+1)=opnd1%10+'0';
}
else
if(opnd1<100 && opnd1!=0) *str=opnd1+'0';
else *str=opnd1;
strcat(str,_keep[i].opercode);
j=strlen(str);
if(_blng(opnd2,10,99))
{
*(str+j)=opnd2/10+'0';
*(str+j+1)=opnd2%10+'0';
}
else
if(opnd2<100) *(str+j)=opnd2+'0';
else *(str+j)=opnd2;
// Сохраняем размер колонки (определяется размером заголовка)
_table.cplc[i]=strlen(str);
i++;
}
// Отрисовываем таблцу
// Готовим горизонтальную черту
char border[300]={'\0'};
strcpy(border," ------");
i=0;
while(i++<_opcount)
{
strcat(border," ");
j=0;
_table.cplc[i]+=2;
while(j++<_table.cplc[i]) strcat(border,"-");
}
strcat(border,"\n");
// Собственно, уже выводим
fprintf(stream,border);
fprintf(stream,"| xyzp |");
i=0;
while(i++<_opcount) fprintf(stream," %s |",_table.head[i]);
fputc('\n',stream);
i=0;
while(i<_B_CNT)
{
if(i%4==0) fprintf(stream,border);
fprintf(stream,"| %d%d%d%d |",_x[i],_y[i],_z[i],_p[i]);
# define h opind
j=0;
while(j++<_opcount)
{
h=_table.cplc[j]-2;
while(h-->0) fputc(' ',stream);
fprintf(stream,"%d |",_table.value[j][i]);
}
# undef h
fputc('\n',stream);
i++;
}
fprintf(stream,border);
fclose(stream);
printf("Таблица успешно сохранена");
i=1;
}
else perror("Не могу создать результирующий \nфайл (\\Table.txt)");
return i;
}
//! .Main
void main(void)
{
int a=0;
clrscr();
a=InitBin("Data\\OpDef.txt");
if(a)
a=ParseBin("Data\\FuncDef.txt");
if(a)
DrawBinTable("Table.txt");
printf("\nНажмите любую клавишу, чтобы выйти...");
getch();
}
// ------------------------------- OpDef.txt ----------------------------------
// Порядок определения знаков для операций:
// 1) Отрицание
// 2) Штрих Шеффера
// 3) Стрелка Пирса
// 4) Запрет х ->
// 5) Запрет у <-
// 6) Конъюнкция
// 7) Дизъюнкция
// 8) Сумма по модулю 2
// 9) Импликация x =>
// 10) Импликация y <=
// 11) Эквивалентность
// Определение знаков (по порядку, каждый знак в фигурных скобках, максимум 5 символов, желательно
// из неповторяющихся, пробел в качестве символа использовать нельзя - он игнорируется
// программой; цифры так же нельзя использовать, они используются программой для нумерации операций):
{!} {/} {$} {->} {<-} {&&} {||} {+} {=>} {<=} {~}
// ------------------------------ FuncDef.txt ---------------------------------
// Определение функции должно быть в фигурных скобках, знаки операций должны соответствовать
// объявленным в соседнем файле OpDef.txt
f(x,y,z,p)={x/y ~ p||x => z&&x$y <- !z + x||z}
// ------------------------------ TABLE.tab -----------------------------------
------ ---- ----- ----- ------ ------ ------ ------ ----- ------ -----
| xyzp | !z | x/y | x$y | 3<-1 | z&&4 | p||x | x||z | 5+7 | 6=>8 | 2~9 |
------ ---- ----- ----- ------ ------ ------ ------ ----- ------ -----
| 0000 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 0001 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
| 0010 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 |
| 0011 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
------ ---- ----- ----- ------ ------ ------ ------ ----- ------ -----
| 0100 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 0101 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
| 0110 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
| 0111 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
------ ---- ----- ----- ------ ------ ------ ------ ----- ------ -----
| 1000 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
| 1001 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
| 1010 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
| 1011 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
------ ---- ----- ----- ------ ------ ------ ------ ----- ------ -----
| 1100 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
| 1101 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
| 1110 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
| 1111 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
------ ---- ----- ----- ------ ------ ------ ------ ----- ------ -----
Если вашу таблицу "развозит", просто отключите "перенос по словам" в меню "Формат"