Лексический анализатор из K&R - C (СИ)
Формулировка задачи:
Здравствуйте помогите пожалуйста! В книге K&R приводится пример небольшого лексического анализатора код которого мне вобщем понятен за исключением этого ungetch(c); return tokentype=NAME;
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXTOKEN 100
#define BUFFSIZE 100
enum { NAME, PARENS, BRACKETS };
int gettoken();
int getch();
void dcl();
void dirdcl();
void ungetch(int);
int tokentype;
int bufp=0;
char token[MAXTOKEN];
char name[MAXTOKEN];
char datatype[MAXTOKEN];
char out[1000];
char buffer[BUFFSIZE];
main() {
while(gettoken() != EOF) {
strcpy(datatype, token); /*first arg of programm must be type(int,char or ...)*/
out[0]='\0';
dcl();
if(tokentype!='\n')
printf("syntax error.\n");
printf("%s: %s %s\n", name, out, datatype);
}
return 0;
}
int gettoken() {
int c, getch();
void ungetch(int);
char *p=token;
while((c=getch()) == ' ' || c == '\t')
;
if(c == '(') {
if((c=getch()) == ')') {
strcpy(token, "()");
return tokentype = PARENS;
} else {
ungetch(c);
return tokentype=')';
}
} else if(c == '[') {
for(*p++=c; (*p++=getch()) != ']';)
;
*p='\0';
return tokentype=BRACKETS;
} else if(isalpha(c)) {
for(*p++=c; isalnum(c=getch());)
*p++=c;
*p='\0';
ungetch(c);
return tokentype=NAME;
} else
return tokentype=c;
}
void dcl() {
int ns;
for(ns=0; gettoken() == '*';)
ns++;
dirdcl();
while(ns-- > 0)
strcat(out, " pointer to");
}
void dirdcl() {
int type;
if(tokentype == '(') {
dcl();
if(tokentype != ')')
printf("error: missing ) \n");
} else if(tokentype == NAME)
strcpy(name, token);
else
printf("error: expected name or ()\n");
while((type=gettoken()) == PARENS || type == BRACKETS) {
if(type == PARENS)
strcat(out, "function returning");
else {
strcat(out, "array");
strcat(out, token);
strcat(out, " of");
}
}
}
int getch() {
return (bufp > 0)? buffer[--bufp] : getchar();
}
void ungetch(int c) {
if(bufp >= BUFFSIZE)
printf("error: too much characters\n");
else
buffer[bufp++]=c;
}Решение задачи: «Лексический анализатор из K&R»
textual
Листинг программы
if (isalpha(c))
{
// Collect alphanum chars
for (*p++ = c; isalnum(c = getch()); )
{
*p++ = c;
}
*p = 0; // Ensure ASCIIZ
ungetch(c); // Return last (Non alphanum) char to input stream
return tokentype = NAME; // Set token type as NAME
}
Объяснение кода листинга программы
В данном коде выполняется функция, которая является лексическим анализатором. Она предназначена для сбора имени (токена типа NAME) из входного потока символов.
- Проверка условия: Если текущий символ является буквой (isalpha), то начинается сбор имени.
- Сбор имени: Используется цикл, который продолжает собирать имя, пока не встретит не буквенно-цифровой символ (isalnum). Для каждого собранного символа выделяется память с помощью оператора new, и затем символ копируется в выделенную память.
- Очистка символа: После сбора имени, последний символ, который не является буквенно-цифровым, помещается обратно в поток с помощью функции ungetch.
- Завершение работы: Выделяемая память освобождается, а переменная tokentype устанавливается в значение NAME, указывая, что собранное имя. Список переменных и их значений:
- c - Текущий символ
- p - Указатель на память, выделенную для хранения имени
- tokentype - Тип токена, в данном случае NAME
- getch() - Функция, которая возвращает следующий символ из входного потока
- ungetch() - Функция, которая возвращает последний символ обратно в поток
- isalpha() - Функция, которая проверяет, является ли символ буквой
- isalnum() - Функция, которая проверяет, является ли символ буквой или цифрой
- new() - Функция, которая выделяет память для создания нового объекта
- delete() - Функция, которая освобождает память, выделенную для объекта
- NAME - Тип токена, указывающий на имя