Синтаксическая проверка программ на C, таких как непарные круглые, квадратные и фигурные скобки - C (СИ)
Формулировка задачи:
Задание:
Упражнение 1.24.
Напишите программу для выполнения примитивной синтаксической проверки программ на C, таких как непарные круглые, квадратные и фигурные скобки. Не забудьте об одинарных и двойных кавычках, управляющих символах и комментариях. (Это сложная программа, если пытаться реализовать самый общий случай.) Нужно ли реализовывать проверку для#define
и если да, то насколько это будет сложно? Пример:#include <stdio.h>
#define M (
#define N )
int main M void N
{
printf("Test\n" N;
}Решение задачи: «Синтаксическая проверка программ на C, таких как непарные круглые, квадратные и фигурные скобки»
textual
Листинг программы
#include <stdio.h>
#include <string.h>
#define MAXSTACK 1000
char pop(char stack[], int size);
char push(char stack[], char elem, int size);
char peek(char stack[], int size);
int is_com(char s);
int is_proc(char s);
int main(void)
{
char stack[MAXSTACK] = {0};
int c, last=0;
int ec, com, error, tri;
com = ec = error = tri = 0;
while(!error && (c = getchar()) != EOF)
{
// trigraphs
if(c == '?' && tri < 2) ++tri;
else if(tri == 2)
{
switch(c)
{
case '?': break;
case '<': c = '{'; break;
case '>': c = '}'; break;
case '(': c = '['; break;
case ')': c = ']'; break;
case '/': c = '\\'; break;
default: tri = 0; break;
}
}
else
tri = 0;
if(c == '\\')
{
if(ec)
ec = 0;
else
ec = 2;
}
// check brackets
if(is_proc(last))
{
// ( [ { } ] )
switch(c)
{
case '(': push(stack, '(', MAXSTACK); break;
case '[': push(stack, '[', MAXSTACK); break;
case '{': push(stack, '{', MAXSTACK); break;
case ')':
if(pop(stack, MAXSTACK) != '(')
error = 1;
break;
case ']':
if(pop(stack, MAXSTACK) != '[')
error = 1;
break;
case '}':
if(pop(stack, MAXSTACK) != '{')
error = 1;
break;
}
}
// check quotes
if(!is_com(last))
{
switch(c)
{
case '\'':
if(is_proc(last))
push(stack, '\'', MAXSTACK);
else if(!ec && last == '\'')
pop(stack, MAXSTACK);
break;
case '"':
if(is_proc(last))
push(stack, '"', MAXSTACK);
else if(!ec && last == '"')
pop(stack, MAXSTACK);
}
}
// Comment open
if(!is_com(last))
switch(c)
{
case '/':
if(com > 0 && !ec)
{
push(stack, 'l', MAXSTACK);
com = 0;
}
else
com = 2;
break;
case '*':
if(com > 0 && !ec)
push(stack, 'c', MAXSTACK);
com = ec = 0;
break;
}
// Comment close
if(is_com(last))
switch(c)
{
case '*':
if(last == 'c')
com = -2;
break;
case '/':
if(com < 0 && !ec)
{
pop(stack, MAXSTACK);
com = 0;
}
break;
case '\n':
if(last == 'l' && !ec)
{
pop(stack, MAXSTACK);
com = 0;
}
break;
}
if(com && !ec && c!='\n' && !tri)
com += com<0? 1: -1;
if(ec==1 && c != '\n')
com = ec = 0;
else if(ec)
--ec;
last=peek(stack, MAXSTACK);
}
if(error || peek(stack, MAXSTACK) != -1)
printf("Error\n");
else
printf("Valid\n");
return 0;
}
char pop(char stack[], int size)
{
int i, c;
for(i = 0; i < size && stack[i]; ++i);
if(i > 0)
{
c = stack[--i];
stack[i] = '\0';
return c;
}
return -1;
}
char push(char stack[], char elem, int size)
{
int i, c;
for(i = 0; i < size && stack[i]; ++i);
if(i < size)
return c = stack[i] = elem;
return -1;
}
char peek(char stack[], int size)
{
int i;
for(i = 0; i < size && stack[i]; ++i);
if(i > 0)
return stack[--i];
return -1;
}
int is_proc(char s)
{
if(s == '\'' || s == '"' || is_com(s))
return 0;
return 1;
}
int is_com(char s)
{
if(s == 'c' || s == 'l' || s == '\\')
return 1;
return 0;
}
Объяснение кода листинга программы
Код проверяет синтаксис программ на C, в частности, парность скобок (круглых, квадратных и фигурных), кавычек (одиночных и двойных) и обратных слешей. Он также обрабатывает триплеры и комментарии. Вот список функций и их описания:
pop(char stack[], int size)- эта функция удаляет и возвращает последний элемент из стека. Если стек пуст, она возвращает-1.push(char stack[], char elem, int size)- эта функция добавляет элемент в стек. Если стек полон (т.е. достиг максимума размера), она возвращает-1. В противном случае она возвращает0, что означает успешное добавление элемента.peek(char stack[], int size)- эта функция возвращает последний элемент в стеке, не удаляя его. Если стек пуст, она возвращает-1.is_proc(char s)- эта функция возвращает0, если символsявляется открывающей фигурной скобкой, открывающей квадратной скобкой или апострофом. В противном случае она возвращает1.is_com(char s)- эта функция возвращает0, если символsявляется закрывающей фигурной скобкой, закрывающей квадратной скобкой или обратным слешем. В противном случае она возвращает1. Список символов и их значений:`>- означает, что символ является закрывающей квадратной скобкой.`>- означает, что символ является закрывающей фигурной скобкой.`>- означает, что символ является обратным слешем.`>- означает, что символ является апострофом.`>- означает, что символ является открывающей квадратной скобкой.`>- означает, что символ является открывающей фигурной скобкой. Вот список переменных и их описания:c- текущий символ ввода.last- последний символ в стеке.com- счетчик комментариев.ec- счетчик прямых слешей.tri- счетчик тройплеров.stack- стек, используемый для отслеживания синтаксиса.error- флаг, устанавливаемый в1, если обнаружена синтаксическая ошибка. Вот список номеров строк и соответствующих действий:- 3 - начало обработки комментариев.
- 5 - начало обработки скобок.
- 7 - начало обработки кавычек.
- 12 - начало обработки обратных слешей.
- 16 - начало обработки триплеров.
- 18 - начало обработки парных скобок.
- 20 - конец обработки парных скобок. Обратите внимание, что некоторые строки могут иметь несколько действий, разделенных запятыми. Каждое действие обрабатывается последовательно.