Синтаксический анализ строки программирования C - PullRequest
0 голосов
/ 14 марта 2012

Я разбираю определение макроса из Makefile на две строки: имя макроса и тело.Например, вот строка определения макроса из моего Makefile:

macro-1 = body-1

Мой код вызывает ошибку шины / ошибку сегментации.

static void parse_macro_def(const char* line)
{
   char* m_name;
   int name_pos = 0;

   int i = 0;
   while(line[i++] != '=')                    //iterate until an equal sign is found
   {
      if(!isspace(line[i]))          //copy characters to m_name  unless the character is whitespace
      {
         m_name[name_pos++] = line[i];
      }
   }
}
m_name[name_pos] = '\0';

Для m_name должно быть установлено значение macro-1. Спасибо за помощь!

Ответы [ 3 ]

1 голос
/ 14 марта 2012

Вы не инициализируете m_name, поэтому он указывает куда угодно, поэтому вы пишете наугад и вылетаете.

Вам необходимо выделить и вернуть пробел или передать пробел (вместе сдлина пробела), гарантируя, что вы не будете перезаписывать в каждом случае.


Обратите внимание, что символы пробела в имени макроса являются ошибкой в ​​определении макроса.Там может быть ведущий пробел;там может быть пробел;но не может быть пробела в середине имени.Теперь, если вы предполагаете, что вам дали действительный Makefile для анализа, вы можете избежать игнорирования этой тонкости.Если вы пишете замену для make, вы не можете.

Если вы ранее не подтвердили наличие знака равенства в строке, вам также следует убедиться, что вы не убежаликонец строки (вы не сканируете за NUL '\0').На самом деле, в надежном коде вы, вероятно, гарантируете это из паранойи.

while (line[i] != '\0' && line[i] != '=')
{
    ...
}

И во время написания этого я понял, что вы увеличиваете i в состоянии while, а затем проверяетеявляется ли следующий символ пробелом в теле цикла.Это немного условно, скажем так.Если вы встретите макрос:

MACRO=value

, вы скопируете = в m_name, когда условие цикла проверяет O.И, AFAICS, вы не будете копировать M.


Обратите внимание, что ваша строка:

m_name[name_pos] = '\0';

находится вне какой-либо функции и, следовательно, синтаксическая ошибка.

0 голосов
/ 14 марта 2012

В вашем коде есть некоторые недостатки, например Вы никогда не будете проверять / копировать первый символ в строке (потому что вы немедленно увеличиваете i). Также m_name очков нигде (это не определено).

В общем, я бы использовал немного другой подход. Я не уверен, где вы хотели бы ожидать пробелы, но сейчас (при условии, что ваш код будет работать) вы объединяете все, например. «Некоторое значение = что-то» (я знаю, что это не будет действительный код) приведет к имени переменной «somevalue» из-за пропуска всех пробелов.

Я бы использовал что-то вроде этого (уже поздно и я сонный, поэтому могу включить несколько ошибок, но должно дать вам некоторое представление о том, что вы можете попытаться сделать):

char name[256];
const char *start = line; // points to beginning of the line
const char *end = strchr(line, '='); // returns a pointer to the position where there's an equal sign (if there's any; 0 otherwise)
if (end) { // only try to parse if there's an equal sign
    for(; start < end && isspace(*start); ++start); // this will effectively remove all leading space characters
    for(; end > start && isspace(*(end - 1)); --end); // this will effectively remove all trailing space characters
    strncpy(name, start, end - start); // copy the name
    // do something else here
}

Кроме того, в зависимости от того, что вы собираетесь делать в других частях, может быть полезно использовать какую-то библиотеку регулярных выражений (если дополнительные издержки того стоят, зависит от вашего проекта) и использовать какое-то выражение вроде \s*(.*?)\s*=.

0 голосов
/ 14 марта 2012

m_name является неопределенным, вы не присвоили ему никакого значения.Возможно, вы захотите присвоить ему возвращаемое значение вызова для malloc или calloc.

Кроме того, ваш цикл будет читать после конца строки, если строка не содержит =.Вы должны убедиться, что ваш цикл завершается, когда он достигает либо =, либо конца строки (который может быть '\n' или '\0' в зависимости от ваших потребностей).

...