Более
совершенный сканер.
Перейдем теперь от нашего примитивного сканера к нормальному. Последовательность действий такая – сперва читаем байты из файла с исходным текстом (Pr_str.txt) в строку. Указатель на эту строку делаем глобальной переменной. И начинаем «идти вдоль» строки (сканировать байт за байтом). Если мы при каком-то вызове функции-сканера закончили просмотр строки на каком-то месте, при следующем вызове продолжим с этого же места (из-за глобальности указателя).
Ниже я привожу программу для испытания сканера. Лексемы она выводит в файл Result.txt.
/****************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "Str_ex.h"
#include "QnS.h"
int I=0;
int n=5;
char Lex[150]; /* Это для лексем */
char End[3]; /* Это конец строки в текстовом файле */
/* Переменные относятся к сканеру */
char Prog[64000]; /* Это для текста программы */
char *pProg; /* Указатель, двигающийся по строке программы */
char LastLex[150]; /* Это для последней лексемы */
char *pProgLast; /* Здесь указатель на начало последней
полученной лексемы */
char *pProgLast2;
/* char SS[50];*/
/* char Sign1[2]={43,0};
char Sign2[2]={45,0};
char Sign3[2]={42,0};
char Sign4[2]={47,0};*/
/******************************/
/*
sprintf(A,"n=%d",n);*/
/******************************/
/* Это - построение сканера */
int isDelim(int S) /* Является ли знак разделителем, */
{
if(S==43|| /* - */
S==45|| /* + */
S==42|| /* * */
S==47|| /* / */
S==37|| /* % */
S==61|| /* = */
S==60|| /* < */
S==62|| /* > */
S==59|| /* ; */
S==40|| /* ( */
S==41|| /* ) */
S==33|| /* ! */
S==44|| /* , */
S==46) /* . */
{
return 1;
}
else
{
return 0;
};
}
int isDelim1(int S,int SNext) /* Является ли знак разделителем, плюс
учет того, что если после точки цифра, то точка уже не разделитель
(чтобы действительное число с дробной точкой не разбивалось) */
{
if(S==43|| /* - */
S==45|| /* + */
S==42|| /* * */
S==47|| /* / */
S==37|| /* % */
S==61|| /* = */
S==60|| /* < */
S==62|| /* > */
S==59|| /* ; */
S==40|| /* ( */
S==41|| /* ) */
S==33|| /* ! */
S==44|| /* , */
S==46) /* . */
{
if(S=='.')
{
if(isdigit(SNext)!=0)
{
return
0;
}
else
{
return
1;
};
}
else
{
return
1;
};
}
else
{
return 0;
};
}
void ErrorScaner(int N)
{
;
if(N==1)
WrStr("Result_0.txt",End,"Unknown Sign - 1-st in Lexema!
",1);
if(N==2)
WrStr("Result_0.txt",End,"No 2-nd quota",1);
return;
}
void NextLexema() /* Получает очередную лексему */
{
char *pLex=(char *)Lex;
if(*pProg==0) /* Если на входе пустая строка */
{
*pLex=0;
return;
}
/* Сохраняем положение указателя на позицию
в тексте программы (если вдруг придется
возвращаться назад): */
pProgLast2=pProgLast;
pProgLast=pProg;
while(isspace(*pProg)) ++pProg; /* Убираем лидирующие пробелы */
if(*pProg==47&&*(pProg+1)==42) /* Обработка комментария */
{
pProg++;
pProg++;
while(!(*pProg==42&&*(pProg+1)==47))
{
if(*pProg==0)
return;
pProg++;
}
pProg++;
pProg++;
/*return;*/
}
while(isspace(*pProg))
++pProg; /* Убираем пробелы после комментария */
if(*pProg==45|| /* - */
*pProg==43|| /* + */
*pProg==42|| /* * */
*pProg==47|| /* / */
*pProg==37|| /* % */
*pProg==61|| /* = */
*pProg==60|| /* < */
*pProg==62|| /* > */
*pProg==59|| /* ; */
*pProg==40|| /* ( */
*pProg==41|| /* ) */
*pProg==33|| /* ! */
*pProg==44|| /* , */
*pProg==46) /* . */
{ /* Это мы рассматриваем знаки */
/***/ /* Обработка двухсимвольных знаков */
if(*pProg==60&&*(pProg+1)==61)
{
*pLex=*pProg;
pProg++;
pLex++;
*pLex=*pProg;
pProg++;
pLex++;
*pLex=0;
return;
}
if(*pProg==62&&*(pProg+1)==61)
{
*pLex=*pProg;
pProg++;
pLex++;
*pLex=*pProg;
pProg++;
pLex++;
*pLex=0;
return;
}
if(*pProg==60&&*(pProg+1)==62)
{
*pLex=*pProg;
pProg++;
pLex++;
*pLex=*pProg;
pProg++;
pLex++;
*pLex=0;
return;
}
if(*pProg==33&&*(pProg+1)==61)
{
*pLex=*pProg;
pProg++;
pLex++;
*pLex=*pProg;
pProg++;
pLex++;
*pLex=0;
return;
}
/***/ /* Теперь - односимвольные */
*pLex=*pProg;
pProg++;
pLex++;
*pLex=0;
return;
}
if(*pProg==34) /* Обработка выражения в кавычках */
{
*pLex=34;
pProg++;
pLex++;
while(*pProg!=34)
{
if(*pProg==0)
{
ErrorScaner(2);
return;
}
*pLex++=*pProg++;
}
pProg++;
*pLex=34;
pLex++;
*pLex=0;
return;
}
if(isdigit(*pProg)) /* Начинаем рассматривать число */
{
int
k=0;
while(k>-1)
{
if(*pProg==0)
{
*pLex=0;
return;
}
if(*pProg==13)
{
*pLex=0;
return;
}
if(*pProg==10)
{
*pLex=0;
return;
}
if(isspace(*pProg)==1)
{
*pLex=0;
return;
}
if(isDelim1(*pProg,*(pProg+1))==1)
{
*pLex=0;
return;
}
*pLex=*pProg;
pLex++;
pProg++;
}
}
if(isalpha(*pProg)) /* Начинаем рассматривать имя переменной или
ключевое слово языка */
{
int
k=0;
while(k>-1)
{
if(*pProg==0)
{
*pLex=0;
return;
}
if(*pProg==13)
{
*pLex=0;
return;
}
if(*pProg==10)
{
*pLex=0;
return;
}
if(isspace(*pProg)==1)
{
*pLex=0;
return;
}
if(isDelim(*pProg)==1)
{
*pLex=0;
return;
}
*pLex=*pProg;
pLex++;
pProg++;
}
}
if(!(isspace(*pProg)!=0||*pProg==0))
ErrorScaner(1);
pProg++;
return;
}
/*******************/
void main(void)
{
Lex[0]=0;
End[0]=13;
End[1]=10;
End[2]=0;
char
dest[200];
/*****/
FILE *f1;
int Ch;
char ch;
int jc,J;
pProg=Prog;
pProgLast=Prog;
pProgLast2=Prog;
f1=fopen("pr_str.txt","rb");
if(f1==NULL)
{
return;
}
jc=0;
J=0;
/* Чтение программы из файла в строку */
while(jc>-1)
{
Ch=fgetc(f1);
if(Ch==EOF)
{
fclose(f1);
break;
};
ch=(char)Ch;
*(pProg+J)=ch;
J++;
}
/*****/
jc=0;
/* Сканируем лексему за лексемой */
while(jc>-1)
{
WrStr("Result.txt",End,"one more lexema",1);
Lex[0]=0;
NextLexema();
WrStr("Result.txt",End,Lex,1);
if(*Lex==0)
break;
}
WrStr("Result.txt",End,"End!!!",1);
/* Проверяем, удастся ли получить предшествующую
лексему */
/*pProg=pProgLast;
NextLexema();
WrStr("Result.txt",End,Lex,1); */
/*pProg=pProgLast2;
NextLexema();
WrStr("Result.txt",End,Lex,1); */
return;
}
/***********************/
Это проект Gramm1_001.