Плюс
унарный плюс (и минус конечно).
Добавим унарные знаки – плюс и минус. Форма Бэкуса-Наура такая:
<expr> := <term> {<add_op><term>}
<term> :=
<signed_factor>{<mul_op><signed_factor>}
<signed_factor> :=
[<add_op>]<factor>
<factor> := <integer>
Дополнительные (к содержимому предыдущей главы) обозначения такие: signed_factor – это множитель со знаком, а просто factor – без знака. Заметим, что, как следует из формы, унарный знак перед числом может быть лишь один (так как add_op пред factor – в квадратных скобках).
В остальном все остается таким
же. Привожу исходный текст программы:
/********************************/
#include <stdio.h>
#include <stdlib.h>
#include "Str_ex.h"
#include "QnS.h"
int
I=0;
int
n=5;
char Lex[150]; /* Это для лексем */
char Res[250]; /* Это для результирующей постфиксной
польской строки */
char End[3]; /* Это конец строки в текстовом файле */
char Sign1[2]={43,0};
char
Sign2[2]={45,0};
char
Sign3[2]={42,0};
char
Sign4[2]={47,0};
char
Sign5[3]={43,85,0};
char
Sign6[3]={45,85,0};
/******************************/
/* sprintf(A,"n=%d",n);*/
/******************************/
/* Это - обработка формулы
со сложением-вычитанием и
умножением-делением, а также
с одним унарным плюсом или минусом (перед каждым числом).
Результат - в польской постфиксной
записи */
int J=1;
void NextLexema() /* Получает очередную лексему */
{
int R;
*Lex=0;
R=FindStrN("Pr.txt",End,Lex,100,J);
J++;
if(R<0)
{
*Lex=0;
WrStr("Lexema.txt",End," THE END! ",1); /* В тестовых
целях
пишем в файл */
return;
}
else
{
WrStr("Lexema.txt",End,Lex,1); /* В тестовых целях
пишем в файл */
};
}
void fact() /* Это множитель - конечный пункт рекурсии */
{
if(testnum_l(Lex)==0&&(*Lex>47&&*Lex<58)) /* Проверка - является ли целым числом */
{
StrCat(Lex,Res);
StrCat(" ",Res);
NextLexema();
}
else
{
CpStr("ERROR",Res);
};
}
void sfact()
{
char
Lex1[150];
Lex1[0]=0;
if(*Lex==43||*Lex==45)
{
CpStr(Lex,Lex1);
NextLexema();
}
fact();
if(*Lex1!=0)
{
StrCat(Lex1,Res);
StrCat("U",Res);
StrCat(" ",Res);
}
}
void term() /* Обработка умножения-деления */
{
char
Lex1[150];
Lex1[0]=0;
sfact();
/*while(COMPstr("*",Lex)==0||COMPstr("/",Lex)==0)*/
while(*Lex==42||*Lex==47)
{
CpStr(Lex,Lex1);
NextLexema();
sfact();
StrCat(Lex1,Res);
StrCat(" ",Res);
}
}
void expr() /* Обработка сложения-вычитания */
{
char
Lex1[150];
Lex1[0]=0;
term();
/*while(COMPstr("+",Lex)==0||COMPstr("+",Lex)==0)*/
while(*Lex==43||*Lex==45)
{
CpStr(Lex,Lex1);
NextLexema();
term();
StrCat(Lex1,Res);
StrCat(" ",Res);
}
}
/********************************/
/* Обработка строки с польской обратной
записью */
int
iPF=1;
int
PostFix(char *S,int L,int N,char *Dest)
{
void * pSt;
char St[100];
int i,res;
int iPF1;
int iPF2;
int iPF3;
char *S1;
void *pS1;
/*char S2[50];
char S3[50];
char S4[100];*/
int r=0;
double F1,F2,F3;
if(*S==0)
{
WrStr("PostFix.txt",End,"Empty!",1);
return -2;
}
pS1=malloc(L);
if(pS1==NULL)
{
return
-1;
}
S1=(char *)pS1;
*S1=0;
/*WrStr("PostFix.txt",End,"Coming",1);*/
pSt=CreateStack(L*N);
while(iPF>0)
{
/*WrStr("PostFix.txt",End,"Cycle",1);*/
iPF1=CpWordN(S,S1,32,iPF);
if(iPF1<0)
{
break;
}
iPF++;
if(!(COMPstr(S1,Sign1)==0||COMPstr(S1,Sign2)==0||COMPstr(S1,Sign3)==0||COMPstr(S1,Sign4)==0||
COMPstr(S1,Sign5)==0||COMPstr(S1,Sign6)==0))
/* Если символ не знак, помещаем в стек */
{
for(i==0;i<100;i++)
*(St+i)=0;
CpStr(S1,St);
res=AddArrayToStackNoPart(pSt,St,100);
if(res!=100)
{
r=-3;
WrStr("PostFix.txt",End,"Stack
error!",1);
}
}
else /* Если символ - знак */
{
if(COMPstr(S1,Sign1)==0||COMPstr(S1,Sign2)==0||COMPstr(S1,Sign3)==0||COMPstr(S1,Sign4)==0)
{
for(i==0;i<100;i++) *(St+i)=0;
res=GetArrayFromStack(pSt,St,100);
if(res!=100)
{
r=-4;
WrStr("PostFix.txt",End,"Stack
error (getting)!",1);
}
F1=atol(St);
for(i==0;i<100;i++) *(St+i)=0;
res=GetArrayFromStack(pSt,St,100);
if(res!=100)
{
r=-5;
WrStr("PostFix.txt",End,"Stack
error (getting)!",1);
}
F2=atol(St);
if(COMPstr(S1,Sign1)==0) /* Если
сложение */
{
F3=F2+F1;
}
if(COMPstr(S1,Sign2)==0) /* Если
вычитание */
{
F3=F2-F1;
}
if(COMPstr(S1,Sign3)==0) /* Если
умножение */
{
F3=F2*F1;
}
if(COMPstr(S1,Sign4)==0) /* Если
деление */
{
F3=F2/F1;
}
sprintf(St,"%f",F3);
/*Кладем результат в стек*/
for(i==0;i<100;i++) *(St+i)=0;
res=AddArrayToStackNoPart(pSt,St,100);
if(res!=100)
{
r=-6;
WrStr("PostFix.txt",End,"Stack
error!",1);
}
}
if(COMPstr(S1,Sign5)==0||COMPstr(S1,Sign6)==0)
{
for(i==0;i<100;i++) *(St+i)=0;
res=GetArrayFromStack(pSt,St,100);
if(res!=100)
{
r=-4;
WrStr("PostFix.txt",End,"Stack
error (getting)!",1);
}
F1=atol(St);
if(COMPstr(S1,Sign6)==0) /* Если
унарный минус */
{
F3=-F1;
}
sprintf(St,"%f",F3);
/*Кладем результат в стек*/
for(i==0;i<100;i++) *(St+i)=0;
res=AddArrayToStackNoPart(pSt,St,100);
if(res!=100)
{
r=-6;
WrStr("PostFix.txt",End,"Stack
error!",1);
}
}
}
}
/*Извлекаем из стека результат*/
for(i==0;i<100;i++) *(St+i)=0;
res=GetArrayFromStack(pSt,St,100);
if(res!=100)
{
r=-7;
WrStr("PostFix.txt",End,"Stack
error (getting)!",1);
}
*S1=0;
StrCat(St,S1);
WrStr("PostFix.txt",End,"Result
in stack: ",1);
WrStr("PostFix.txt",End,S1,1);
/* Конец извлечения результата из стека*/
CpStr(S1,Dest);
DeleteStack(pSt);
free(pS1);
return r;
}
/*******************/
void
main(void)
{
Lex[0]=0;
Res[0]=0;
End[0]=13;
End[1]=10;
End[2]=0;
char dest[200];
NextLexema();
expr(); /* Это вход в разбор формулы */
WrStr("Result.txt",End,Res,1); /* Записываем результирующую
польскую постфиксную строку
в файл */
PostFix(Res,100,100,dest);
WrStr("Result.txt",End,"А
число:",1);
WrStr("Result.txt",End,dest,1);
return;
}
/***************************************/
Как напоминание самому себе: этот проект в папке Gramm2. Напоминаю здесь же, что в проект входят и файлы библиотек (.lib), где помещены многие написанные мной полезные функции.