Лекс Плай не считая входит - PullRequest
0 голосов
/ 08 июня 2018

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

def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

Это не считает меня строк, вотпример ввода и вывода:

for
if
else
switch
exit
Number of if´s: 1
Number of for´s: 1
Number of While´s: 0
Number of else´s: 1
Number of switche´s: 1
Number of lines: 1

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

Traceback (последний вызов был последним): файл "C: /Users/User/PycharmProjects/practicas/firma_digital.py", строка 80, если tok.type не равен None: AttributeError: 'NoneType'У объекта нет атрибута 'type'

Вот весь мой код:

import ply.lex as lex
import ply.yacc as yacc
FinishProgram=0
Enters=0
Fors=0
Whiles=0
ifs=0
elses=0
Switches=0

reserved = {
   'if' : 'IF',
   'for' : 'FOR',
   'while': 'WHILE',
   'else': 'ELSE',
   'switch': 'SWITCH'
}
tokens = [
    'ID',
    'COLON',
    'SEMICOLON',

    ]+ list(reserved.values()) #Palabras reservadas

t_COLON= r','
t_SEMICOLON=r';'


def t_ID(t):
    r'[a-zA-Z_][a-zA-Z0-9_]*'
    t.type = reserved.get(t.value, 'ID')
    return t

t_ignore=r' '

def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)

def t_error(t):
    print("This thing failed")
    t.lexer.skip(1)

lexer=lex.lex()


#def p_gram_sets(p):
 #   '''

  #  gram : SETS SEMICOLON
   #      | empty
    #'''
    #if p[1]:
     #   print(p[1])
      #  print("SETS")



def p_empty(p):
    '''
    empty :
    '''
    p[0]=None





def p_error(p):
    print("Syntax error in input!")


parser=yacc.yacc()

while FinishProgram==0:
    s=input('')
    lexer.input(s)
    tok = lexer.token()

    if tok.type is not None:
        if tok.type=='IF':
            ifs+=1
        elif tok.type=='FOR':
            Fors+=1
        elif tok.type=='WHILE':
            Whiles+=1
        elif tok.type=='ELSE':
            elses+=1
        elif tok.type=='SWITCH':
            Switches+=1

    #parser.parse(s)
    if "exit" in s:
        print("Number of if´s: "+ str(ifs) + "\n"+"Number of for´s: "+str(Fors)+"\n"+"Number of While´s: "+str(Whiles)+"\n"+"Number of else´s: "+str(elses)+"\n"+"Number of switche´s: "+str(Switches)+"\n"+"Number of lines: "+str(tok.lineno))
        FinishProgram=1

1 Ответ

0 голосов
/ 08 июня 2018

Это не значит, что ply не считает символы новой строки.Он их никогда не видит, потому что вы вызываете его несколько раз, используя input().

Из документов Python (выделение добавлено):

input ([prompt])

Если аргумент подсказки присутствует, он записывается в стандартный вывод без завершающей строки.Затем функция читает строку из ввода, преобразует ее в строку (, удаляя завершающий символ новой строки ), и возвращает ее.

Обычно lex.lex используется для

Кроме того, вы печатаете

... + str(tok.lineno)

вместо

... + str(lexer.lineno)

После токенизации последнего токена lex.lex возвращает None, так что вы можете ожидать tok будет Null, когда ваш цикл завершится, и поэтому попытка извлечь его атрибут lineno будет ошибкой.(Однако в вашем случае это происходит только в том случае, если строка, которую вы только что попытались токенизировать, была пустой, потому что вы используете только первый токен в каждой строке.) Вы хотите, чтобы количество строк записывалось в объект лексера, то есть количество, которое вы обновляете вваше действие.

Если вы хотите работать с целым файлом (что обычно для синтаксических анализаторов, кроме построчных калькуляторов), вам необходимо прочитать все содержимое файла (или стандартный ввод).в зависимости от обстоятельств).Для неинтерактивного использования вы обычно делаете это с функцией read файлового объекта.Если вы хотите протестировать свой лексер, вы должны использовать тот факт, что функция lex реализует итерационный протокол Python, поэтому она будет работать в операторе for.Таким образом, ваш основной цикл будет выглядеть примерно так:

import sys
lexer.input(sys.stdin.read())
for tok in lexer:
  # Update counts

, и вы завершите ввод, введя символ конца файла в начале строки (control-D в Linux или control-Z вWindows).

Лично я бы реализовал подсчет типов токенов с помощью defaultdict:

from collections import defaultdict
counts = defaultdict(int)
for tok in lexer:
  counts[tok.type] += 1
for type, count in counts.items():
  print ("Number of %s's: %d\n" % (type, count))
# Or: print('\n'.join("Number of %s's: %d\n" % (type, count) for type, count in counts.items())
print ("Number of lines: %d\n" % lexer.lineno)
...