层的Lex不算进入

时间:2018-06-08 17:32:25

标签: python ply

我试图做一个计算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

但是每当我按Enter键编写一行新代码时,它都不会被计算,如果我按Enter键而不写任何内容,则会出现此错误:

  

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 :(得分:1)

并不是说ply不计算换行符。它从未见过它们,因为您使用input()重复调用它。

从Python文档(强调添加):

  

输入([提示])

     

如果存在prompt参数,则将其写入标准输出而不带尾随换行符。然后该函数从输入中读取一行,将其转换为字符串(剥离尾随换行符),然后返回该行。

lex.lex的正常用法是

此外,您正在打印

... + str(tok.lineno)

而不是

... + str(lexer.lineno)

在最后一个令牌被标记后,lex.lex返回None,因此当您的循环终止时,您可以期望tokNull,因此它是错误的尝试提取它的lineno属性。 (但是,在您的情况下,只有在您尝试标记的行为空时才会发生这种情况,因为您只使用每行上的第一个标记。)您希望记录在词法分析器对象中的行数,这是您更新的计数你的行动。

如果你想处理整个文件(这是解析器的常见情况,而不是逐行计算器),你需要读取文件的全部内容(或者stdin,视情况而定) )。对于非交互式使用,通常使用文件对象的read函数来执行此操作。如果您想测试词法分析器,那么您将使用lex函数实现Python迭代协议的事实,因此它将在for语句中工作。所以你的主循环就像:

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

并且您将通过在行的开头键入文件结尾字符来终止输入(Linux上的control-D或Windows上的control-Z)。

就个人而言,我会使用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)