2016-10-08 23 views
-1
%{ 
#undef yywrap 
#define yywrap() 1 
#include<stdio.h> 
    int statements = 0; 
    int ids = 0; 
    int assign = 0; 
    int rel = 0; 
    int keywords = 0; 
    int integers = 0; 
%} 
DIGIT [0-9] 
LETTER [A-Za-z] 
TYPE int|char|bool|float|void|for|do|while|if|else|return|void 
%option yylineno 
%option noyywrap 

%% 
\n {statements++;} 
{TYPE} {/*printf("%s\n",yytext);*/keywords++;} 
(<|>|<=|>=|==) {rel++;} 
'#'/[a-zA-Z0-9]* {;} 
[a-zA-Z]+[a-zA-Z0-9]* {printf("%s\n",yytext);ids++;} 
= {assign++;} 
[0-9]+ {integers++;} 
.  {;} 

%% 
void main(int argc, char **argv) 
{ 
    FILE *fh; 
    if (argc == 2 && (fh = fopen(argv[1], "r"))) { 
    yyin = fh; 
    } 
    yylex(); 
    printf("statements = %d ids = %d assign = %d rel = %d keywords = %d integers = %d \n",statements,ids,assign,rel,keywords,integers); 
} 

// Входной file.cLex/сгибать программа для подсчета IdS, утверждения, ключевые слова, операторы и т.д.

#include<stdio.h> 
void main(){ 
    float a123; 
    char a; 
    char b123; 
    char c; 
    int ab[5]; 
    int bc[2]; 
    int ca[7]; 
    int ds[4]; 
    for(a = 0; a < 5 ;a++) 
    printf("%d ", a); 
    return 0; 
} 

выход:

include 
stdio 
h 
main 
a123 
a 
b123 
c 
ab 
bc 
ca 
ds 
a 
a 
a 
printf 
d 
a 
statements = 14 ids = 18 assign = 1 rel = 3 keywords = 11 integers = 7 

Я печати идентификаторы на ходу , #include<stdio.h> подсчитывается как идентификатор. Как мне избежать этого?

Я пробовал '#'/[a-zA-Z0-9]* {;} правило: действие пара, но оно все еще считается как идентификатор. Как файл символизируется?

Также строка %d в printf подсчитывается как идентификатор. Я явно написал, что идентификаторы должны начинаться только с букв, тогда почему %d определяется как идентификатор?

+0

Директивы препроцессора всегда находятся в одной строке. Директива include начинается с '#' ключевого слова 'include' и строки, представляющей путь, расположенный между угловыми скобками.'% D' в строке анализируется как ' d ', потому что'% 'падает. Содержимое строкового литерала получает синтаксический анализ, потому что вы не обнаруживаете строковые литералы. Строковые литералы - это что-либо между' '' except '' '(кроме if escaped' \ "', но это может быть другое червей). Но вы в последний раз находитесь на хорошем пути. – deamentiaemundi

+0

Итак, как мне избежать «#include » и «% d»? Я получаю 'stdio' и' h' в качестве ключевых слов, как это соответствует определению, которое я дал? Что случилось с «.» Между ними? – piepi

+0

Вы не можете считать операторы с помощью * lex/flex *. Вам нужно проанализировать это. – EJP

ответ

2
  1. Я попытался '#'/[a-zA-Z0-9]* {;} правила: пара действий, но это [include] по-прежнему считается идентификатором. Как файл символизируется?

    Токены распознаются по одному. Каждый токен начинается с завершения предыдущего токена.

    '#'/[a-zA-Z0-9]* матчи '#' при условии его следует [a-zA-Z0-9]*. Вероятно, вы имели в виду "#"/[a-zA-Z0-9]* (с двойными кавычками), которое соответствовало бы #, при условии, что за ним следует буква или цифра. Обратите внимание, что сопоставляется только #; шаблон после / - это «конечный контекст», который в основном является прогнозом для просмотра. В этом случае lookahead бессмысленна, потому что [a-zA-Z0-9]* может соответствовать пустой строке, поэтому любые # будут сопоставляться. В любом случае после того, как # сопоставляется как токен, сканирование продолжается на следующем символе. Таким образом, следующий токен будет include.

    Из-за опечатки этот шаблон не совпадает. (В источнике нет апострофов.) Итак, что на самом деле совпадает с вашим «резервным» правилом: правило с шаблоном .. (Мы называем это резервным правилом, потому что оно соответствует чему-либо. Действительно, оно должно быть .|\n, так как . соответствует чему-либо, кроме символа новой строки, но до тех пор, пока у вас есть правило, соответствующее символу новой строки, допустимо использовать .. «т поставить правило резервный, один будет вставлен автоматически прогибается с действием ECHO.)

    Таким образом, # игнорируется (так же, как это было бы, если бы вы написали правила по назначению) и снова сканирование продолжается с помощью токена include.

    Если вы хотите, чтобы игнорировать всю директиву препроцессора, вы могли бы сделать что-то вроде

    ^[[: пусто:]] #.* {; }

  2. (с комментариями) Я получаю stdio и h в качестве ключевых слов, как это вписывается в определение, которое я дал? Что случилось с . между ними?

    После < игнорируется правило запасного варианта, stdio подобран. Поскольку [a-zA-Z]+[a-zA-Z0-9]* не соответствует ничем, кроме букв и цифр, . не считается частью токена. Затем . соответствует и игнорируется правилом возврата, а затем сопоставляется h.

  3. Также %d строка в printf в настоящее время считается идентификатором.

    Не совсем. % явно игнорируются правилом перехода на аварийном режиме (как это было "), а затем d будет маршировали в качестве идентификатора. Если вы хотите, чтобы игнорировать слова в строковых литералах, вы должны распознавать и игнорировать строковые литералы.

+0

Где я могу узнать о правилах 'fallback'? – piepi

+0

@piepi: Это просто неофициальное описание. Как правило, гибкие наборы правил заканчиваются правилом, чей шаблон равен '. \ N', который соответствует любому одиночному символу; мы называем это «резервным» правилом, потому что, если ничего не работает, лексер возвращается к этому правилу. Иногда можно использовать более простой шаблон '.', потому что какое-то другое правило соответствует' \ n' (как в вашем примере), но лучше всего написать резервный шаблон в полном объеме, на всякий случай. Если вы не укажете '% option nodefault', flex введет правило возврата по умолчанию, действие которого« ECHO ». – rici