2016-07-13 3 views
2

Я написал программу для анализатора lex (небольшой код), которая будет определять ключевые слова, идентификаторы и константы. Я беру строку (исходный код C как строку), а затем преобразовываю ее в слова.Программа Lexical Analyzer C для идентификации токенов

#include <stdio.h> 
#include <conio.h> 
#include <string.h> 

char symTable[5][7] = { "int", "void", "float", "char", "string" }; 

int main() { 
    int i, j, k = 0, flag = 0; 
    char string[7]; 
    char str[] = "int main(){printf(\"Hello\");return 0;}"; 
    char *ptr; 
    printf("Splitting string \"%s\" into tokens:\n", str); 
    ptr = strtok(str, "(){};"""); 
    printf("\n\n"); 
    while (ptr != NULL) { 
     printf ("%s\n", ptr); 

     for (i = k; i < 5; i++) { 
      memset(&string[0], 0, sizeof(string)); 
      for (j = 0; j < 7; j++) { 
       string[j] = symTable[i][j]; 
      } 

      if (strcmp(ptr, string) == 0) { 
       printf("Keyword\n\n"); 
       break; 
      } else 
      if (string[j] == 0 || string[j] == 1 || string[j] == 2 || 
       string[j] == 3 || string[j] == 4 || string[j] == 5 || 
       string[j] == 6 || string[j] == 7 || string[j] == 8 || 
       string[j] == 9) { 
       printf("Constant\n\n"); 
       break; 
      } else { 
       printf("Identifier\n\n"); 
       break; 
      } 
     } 
     ptr = strtok(NULL, "(){};"""); 
     k++; 
    } 
    _getch(); 
    return 0; 
} 

С приведенным выше кодом я могу определить ключевые слова и идентификаторы, но я не смог получить результат для чисел. Я пробовал использовать strspn(), но безрезультатно. Я даже заменил 0,1,2...,9 на '0','1',....,'9'.

Любая помощь будет оценена по достоинству.

+2

В чем именно заключается эта длинная цепочка логических-ИЛИ-терминов, которые должны выполняться? И почему вы проверяете значения 'int' на строку, которую вы просто (странно) скопировали из вашего' symTable [] '? Я думаю, что ['isdigit()'] (http://en.cppreference.com/w/c/string/byte/isdigit) находится в меню этой задачи. – WhozCraig

+0

Для переносных программ не используйте файлы заголовков, которые не являются стандартными. И.Е. не используйте 'conio.h' Вместо' _getch() 'используйте это:' int ch; while ((ch = getchar())! = EOF && '\ n'! = Ch); getchar(); ' – user3629249

+0

для удобства чтения и понимания, 1) следовать аксиоме: * только один оператор в строке и (самое большее) одно объявление переменной для каждого оператора. * 2) имена переменных должны указывать на« контент »или« использование » '(или лучше, оба). 3) при компиляции всегда включайте все предупреждения, затем исправьте эти предупреждения. 4) отдельные блоки кода (для if, else, while, do ... while, switch, case, default) через пустую строку – user3629249

ответ

0

Когда вы пишете лексер, всегда создает определенную функцию, которая находит ваши маркера (имя yylex используются для инструмента System Lex, поэтому я использовал это имя). Написание lexer в основном - не умная идея, особенно если вы хотите сделать синтаксис, семантический анализ позже.

С вашего вопроса неясно, хотите ли вы просто выяснить, что такое токены числа, или хотите ли вы использовать токен + выборку числа. Предполагаю сначала.

Это пример кода, который находит целые числа:

int yylex(){ 

    /* We read one char from standard input */ 
    char c = getchar(); 

    /* If we read new line, we will return end of input token */ 
    if(c == '\n') 
     return EOI; 

    /* If we see digit on input, we can not return number token at the moment. 
     For example input could be 123a and that is lexical error */ 
    if(isdigit(c)){ 

     while(isdigit(c = getchar())) 
      ; 

     ungetc(c,stdin); 
     return NUM; 
    } 

    /* Additional code for keywords, identifiers, errors, etc. */ 
} 

Лексемы EOI, NUM и т.д., должны быть определены на вершине. Позже, когда вы хотите написать синтаксический анализ, вы используете эти токены, чтобы выяснить, отвечает ли код синтаксису языка или нет. В лексическом анализе обычно значения ASCII вообще не определены, например, функция lexer просто возвращает ')'. Зная, что токены должны быть определены выше 255 значений. Например:

#define EOI 256 
#define NUM 257 

Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.

0

string[j]==1

Этот тест является неправильным(1) (на всех реализаций C я слышал), так как string[j] некоторые char например используя ASCII (или UTF-8, или даже старый EBCDIC, используемый на мэйнфреймах IBM), а кодировка цифры char 1 не является номером 1. На моей машине Linux/x86-64 (и на большинстве машин, использующих ASCII или UTF- 8, например, почти все из них) с использованием UTF-8, то характер1 кодируется как байт кода 48 (то есть (char)48 == '1')

вы, вероятно, хотите

string[j]=='1' 

и вы должны рассмотреть возможность использования стандарт isdigit (и родственная) функция.

Следует иметь в виду, что UTF-8 практически используется everywhere, но является многобайтным кодированием (из отображаемых символов). См. Это answer.


Примечание (1): тест string[j]==1 вероятно неуместны тоже! Возможно, вы можете проверить isdigit(*ptr) в лучшем месте.

PS. Пожалуйста, примите во внимание компиляцию со всеми предупреждениями и информацией об отладке (например, с помощью gcc -Wall -Wextra -g при использовании GCC ...) и используйте отладчик (например, gdb). Вы должны узнать свою ошибку за меньшее время, чем потребовалось вам, чтобы получить ответ здесь.

2

Вот некоторые проблемы в вашем парсер:

  • Тест string[j] == 0 не проверяет, является string[j] цифра 0. Символы для цифр записываются '0' - '9', их значения от 48 до 57 в ASCII и UTF-8. Кроме того, вы должны сравнивать *p вместо string[j], чтобы проверить, есть ли у вас цифра в строке, указывающей начало номера.

  • Расщепление строка с strtok() не очень хорошая идея: она изменяет строку и записывает первый разделитель символ с '\0': это предотвратит соответствие операторов, таких как (, ) ...

  • строка "(){};""" точно такая же, как "(){};". Для того чтобы избежать " внутри строк, вы должны использовать \".

Чтобы написать лексер для C, вы должны перейти на первый символ и проверьте следующие символы в зависимости от значения первого символа:

  • если у вас есть пустое пространство, пропустите его
  • если у вас есть //, это комментарий строки: пропустите все символы до новой строки.
  • если у вас есть /*, это комментарий блока: пропустите все символы, пока не получите пару */.
  • , если у вас есть ', у вас есть постоянная символа: проанализируйте символы, обрабатывая escape-последовательности, пока не получите закрытие '.
  • если у вас есть ", у вас есть буквально буквально. сделать то же, что и для символьных констант.
  • Если у вас есть цифра, используйте все последующие цифры, у вас есть целое число. Анализ синтаксиса полного числа требует гораздо большего количества кода: оставьте это позже.
  • если у вас есть буква или символ подчеркивания: используйте все последующие буквы, цифры и символы подчеркивания, а затем сравните слово с набором предопределенных ключевых слов. У вас есть либо ключевое слово, либо идентификатор.
  • В противном случае у вас есть оператор: проверьте, являются ли следующие символы частью оператора с символом 2 или 3 символа, например == и >>=.

Это о нем для простого анализатора C.Полный синтаксис требует больше работы, но вы получите там один шаг за раз.

Смежные вопросы