Пытаюсь написать парсер Си-кода для подсветки синтаксиса. На входе Си-файл, на выходе html-страница. Предназначен для внутренних нужд, но при надобности можно и для внешних нужд (на сервере). Самый парсер я уже написал (ссылка внизу), и вроде бы он работает. У меня несколько вопросов по языку Си.
Терминология: строковые константы вида
"<html>\n" я называю литералами.
Вопрос-1.
Пример Си-кода, выдающего html-страницу. Эту html-страницу можно открыть в браузере. Глобальный массив, определённый как:
const char *kodirovka[] = {...}; -работает. А определённый как:
const char **kodirovka = {...}; -не работает (закомментирован).
// строка 1. Для привязки нумерации строк.
// /home/test/SI/SI/parser_c_cod_2/zprint.c
// cd /home/test/SI/SI/parser_c_cod_2/
// gcc zprint.c -o zprint.cgi -Wall -Werror -O3
// ./zprint.cgi
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
// set KODIROVKA from array kodirovka[]
// установить кодировку из массива kodirovka. Это для выдачи
// кодировки в HTTP-заголовке и в МЕТА-данных html-страницы.
#define KODIROVKA 1
// глобальный массив
const char *kodirovka[] = {
"windows-1251", // (0)
"utf-8", // (1)
};
/*
// глобальный массив
const char **kodirovka = {
"windows-1251", // (0)
"utf-8", // (1)
};
*/
//const char *kod = kodirovka[KODIROVKA]; // глобальная, METKA-1 =====
//----------- set_kod -------------------
const char *set_kod(const char **kodirovka)
{
int k = KODIROVKA;
return(kodirovka[k]);
}
//const char *kod = set_kod(kodirovka); // глобальная, METKA-2 =======
//-------------------- main -------------------
int main(int argc, char const **argv)
{
FILE *fp2;
char const *f1="zprint.html";
const char *kod = kodirovka[KODIROVKA]; //========= METKA-3 ======
//const char *kod = set_kod(kodirovka); //========= METKA-4 ======
printf("kod=%s\n", kod);
fp2=fopen(f1, "w");
if(fp2==NULL){ printf("fp1=fopen(%s)=NULL\n", f1); exit(0);}
fprintf(fp2, "<html>\n");
fprintf(fp2, "<head>\n");
fprintf(fp2, "<title>p_C_2</title>\n");
fprintf(fp2, "<meta charset=\"%s\">\n", kod); // кодировка
fprintf(fp2, "</head>\n");
fprintf(fp2, "<body>\n");
fprintf(fp2, "<a href=\"index.html\">Главная</a>\n");
fprintf(fp2, "<style>body {background-color: #e0e0ff;}</style>\n");
fprintf(fp2, "<style>p {background:#ffffff}</style>\n");
fprintf(fp2, "<p>Proba---Проба</p>\n");
fprintf(fp2, "</body></html>\n");
exit(0);
}
Комилятор со вторым определением (закомментировано) выдаёт:
Код:
$ gcc zprint.c -o zprint.cgi -Wall -Werror -O3
zprint.c:31:5: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
"windows-1251", // (0)
^
zprint.c:31:5: note: (near initialization for ‘kodirovka’)
zprint.c:32:5: error: excess elements in scalar initializer [-Werror]
"utf-8", // (1)
^
zprint.c:32:5: note: (near initialization for ‘kodirovka’)
cc1: all warnings being treated as errors
$
Почему так? Казалось бы, две строки об одном и том же
const char *kodirovka[] = ... -работает.
const char **kodirovka = ... -не работает.
И в аргументах функции
const char *set_kod(const char **kodirovka);массив определён по второму варианту, нерабочему, но работает. Моё предположение: когда память под массив уже выделена, то можно без квадратных скобок, а если ещё не выделена, то нужны квадратные скобки.
Вопрос-2.
Переменая
const char *kod в парсере и в серверной обёртке парсера используется в трёх функциях, и я хотел сделать её глобальной. Но не получилось. В программе выше есть 4 метки, ими помечены кусочки кода, причастные к вопросу. Пробовал активировать каждую из них по отдельности. Глобальные (METKA-1, METKA-2) не работают. Выдача компилятора:
Для METKA-1
Код:
$ gcc zprint.c -o zprint.cgi -Wall -Werror -O3
zprint.c:36:19: error: initializer element is not constant
const char *kod = kodirovka[KODIROVKA]; // ���������, METKA-1 =====
^
$
Для METKA-2
Код:
$ gcc zprint.c -o zprint.cgi -Wall -Werror -O3
zprint.c:47:19: error: initializer element is not constant
const char *kod = set_kod(kodirovka); // ����������, METKA-2 =======
^
$
А локальные (МЕТКА-3, МЕТКА-4) работают. Почему так? Подозреваю, что это баг компилятора.
Вопрос-3.
Фрагмент Си-кода:
printf("Content-type: text/html; charset=windows-1251\n\n");
printf("<html>\n"
"<head>\n"
"<title>p_C_2</title>\n"
"</head>\n"
"<body>\n"
....
Здесь все литералы конкатенационно склеиваются, и получается один большой литерал. У меня это работает, но будет ли это работать на всех компьютерах? Существует ли правило, согласно которому последовательные литералы, не разделённые запятыми, склеиваются в один литерал?
Вопрос-4.
Верно ли, что вся латиница, все символы ASC-ii кода всгда в этом ASC-коде? Т. е. собственно Си-программа в ASC-коде, и только в литералах и в комментариях могут встретиться символы в других кодировках? Верно ли это хотя бы в абсолютном большинстве компьютеров, кроме какой-нибудь экзотики?
Парсер Си-кода (25 кб). При запуске программы:
Первым аргументом указать исходный файл ***.c
Вторым аргументом указать выходной файл ***.html
http://paste.org.ru/index.pl?8jnxg4