int soma = a + b;
while (count < 10) {
sum = sum + value;
count = count + 1;
}
letra(letra|dígito|_)*
[a-zA-Z][a-zA-Z0-9_]*
dígito+
[0-9]+
dígito+\.dígito+
[0-9]+\.[0-9]+
nome
, x1
, contador_total
:%{
/* Código C de configuração */
%}
/* Definições */
DIGITO [0-9]
ID [a-zA-Z][a-zA-Z0-9_]*
%%
/* Regras */
{DIGITO}+ { return NUM; }
{ID} { return ID; }
"+" { return MAIS; }
%%
/* Código auxiliar */
int main() {
yylex();
return 0;
}
import ply.lex as lex
# Lista de nomes de tokens
tokens = (
'NUMBER',
'PLUS',
'MINUS',
'TIMES',
'DIVIDE',
'ID',
)
# Expressões regulares para tokens simples
t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIVIDE = r'/'
# Expressão regular com ação para números
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t
# Expressão regular para identificadores
def t_ID(t):
r'[a-zA-Z][a-zA-Z0-9_]*'
return t
# Caracteres ignorados (espaços e tabs)
t_ignore = ' \t'
# Construir o lexer
lexer = lex.lex()
def t_NOME_DO_TOKEN(t):
r'expressão_regular'
# código Python opcional
return t
# Exemplo de função para reconhecer números
def t_NUMBER(t):
r'\d+'
# Converte string para inteiro
t.value = int(t.value)
return t
# Exemplo para palavras-chave
def t_ID(t):
r'[a-zA-Z][a-zA-Z0-9_]*'
# Verifica se é palavra-chave
if t.value in keywords:
t.type = t.value.upper()
return t
# Espaços e tabulações
t_ignore = ' \t'
# Quebras de linha
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
def t_error(t):
print(f"Caractere ilegal '{t.value[0]}'")
print(f"na linha {t.lexer.lineno}")
t.lexer.skip(1)
# Construir o lexer
lexer = lex.lex()
# Texto de entrada para teste
data = '''
x = 10 + y * 5
if (contador > 20) {
resultado = 30;
}
'''
# Fornecer a entrada ao lexer
lexer.input(data)
# Tokenizar
for tok in lexer:
print(tok)
LexToken(ID,'x',2,1)
LexToken(EQUALS,'=',2,3)
LexToken(NUMBER,10,2,5)
LexToken(PLUS,'+',2,8)
LexToken(ID,'y',2,10)
LexToken(TIMES,'*',2,12)
LexToken(NUMBER,5,2,14)
LexToken(IF,'if',3,16)
LexToken(LPAREN,'(',3,19)
LexToken(ID,'contador',3,20)
...
import ply.lex as lex
# Lista de tokens
tokens = ('NUMBER', 'ID')
# Regras
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t
def t_ID(t):
r'[a-zA-Z][a-zA-Z0-9_]*'
return t
# Ignorar espaços
t_ignore = ' \t\n'
# Tratamento de erros
def t_error(t):
print(f"Caractere ilegal: {t.value[0]}")
t.lexer.skip(1)
# Construir lexer
lexer = lex.lex()
# Adicionar à lista de tokens
tokens = ('NUMBER', 'ID',
'PLUS', 'MINUS', 'TIMES', 'DIVIDE')
# Regras para operadores
t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIVIDE = r'/'
# Testar com
data = "x = 10 + y * 5 - z / 2"
lexer.input(data)
for tok in lexer:
print(tok)
# Entrada para teste
data = '''
a = 10.5;
b = 20;
resultado = (a + b) * 2;
// Este é um comentário
c = 3.14159;
@erro // caractere inválido
'''
# Executar o lexer
lexer.input(data)
for tok in lexer:
print(tok)
LexToken(ID,'a',2,1)
LexToken(EQUALS,'=',2,3)
LexToken(FLOAT,10.5,2,5)
LexToken(SEMICOLON,';',2,9)
LexToken(ID,'b',3,1)
...
Caractere ilegal: @ na linha 7, posição 1
LexToken(ID,'erro',7,2)
if
, else
e while
==
, !=
, >
, <
, >=
, <=
//
e de bloco /* ... */
class Token:
def __init__(self, type, value, line, position):
self.type = type # Categoria (ID, NUM, etc.)
self.value = value # Lexema (texto real)
self.line = line # Linha no código
self.position = position # Posição na linha
# O objeto token no PLY
print(tok.type) # Tipo do token
print(tok.value) # Valor/lexema
print(tok.lineno) # Linha
print(tok.lexpos) # Posição no texto
# Implementação simples em Python
class SymbolTable:
def __init__(self):
self.symbols = {}
def insert(self, name, type=None):
if name not in self.symbols:
self.symbols[name] = {
'type': type,
'line': [],
'used': False
}
def lookup(self, name):
return name in self.symbols
def get_info(self, name):
if self.lookup(name):
return self.symbols[name]
return None
import ply.lex as lex
# Palavras-chave da linguagem
keywords = {'if', 'else', 'while', 'int', 'float'}
# Tabela de símbolos
symbol_table = {}
tokens = ['ID', 'NUMBER'] + [k.upper() for k in keywords]
def t_ID(t):
r'[a-zA-Z][a-zA-Z0-9_]*'
# Verifica se é uma palavra-chave
if t.value in keywords:
t.type = t.value.upper()
else:
# Registra na tabela de símbolos
if t.value not in symbol_table:
symbol_table[t.value] = {
'type': None,
'lines': [t.lineno],
'declared': False
}
else:
symbol_table[t.value]['lines'].append(t.lineno)
return t
# Comentários de linha
def t_COMMENT_LINE(t):
r'//.*'
# Ignora o comentário (não retorna token)
pass
# Comentários de bloco (multi-linha)
def t_COMMENT_BLOCK(t):
r'/\*(.|\n)*?\*/'
# Conta novas linhas no comentário
t.lexer.lineno += t.value.count('\n')
# Ignora o comentário
pass
# String com aspas duplas
def t_STRING(t):
r'"([^"\\]|\\.)*"'
# Remove as aspas
t.value = t.value[1:-1]
# Processa sequências de escape
t.value = t.value.replace('\\n', '\n')
t.value = t.value.replace('\\t', '\t')
t.value = t.value.replace('\\"', '"')
return t
# Erro para string não fechada
def t_error_string(t):
r'"([^"\\]|\\.)*\n'
print(f"String não fechada na linha {t.lexer.lineno}")
t.lexer.skip(len(t.value))
# Operadores de comparação compostos
t_EQUALS = r'=='
t_NOTEQUALS = r'!='
t_LESSEQUAL = r'<='
t_GREATEREQUAL = r'>='
# Operadores simples (devem vir depois dos compostos!)
t_ASSIGN = r'='
t_LESS = r'<'
t_GREATER = r'>'
def t_NUMBER(t):
r'0x[0-9a-fA-F]+|0b[01]+|0o[0-7]+|\d+(\.\d+)?'
# Hexadecimal
if t.value.startswith('0x'):
t.value = int(t.value[2:], 16)
# Binário
elif t.value.startswith('0b'):
t.value = int(t.value[2:], 2)
# Octal
elif t.value.startswith('0o'):
t.value = int(t.value[2:], 8)
# Ponto flutuante
elif '.' in t.value:
t.value = float(t.value)
# Decimal
else:
t.value = int(t.value)
return t
# Definição de estados
states = (
('string', 'exclusive'),
('comment', 'exclusive'),
)
def t_begin_string(t):
r'"'
t.lexer.string_start = t.lexer.lexpos
t.lexer.begin('string') # Muda para estado string
def t_string_end(t):
r'"'
t.lexer.begin('INITIAL') # Volta ao estado normal
# Obtém o conteúdo da string
t.value = t.lexer.lexdata[t.lexer.string_start:t.lexer.lexpos]
t.type = 'STRING'
return t
import io
import ply.lex as lex
import unittest
class TestLexer(unittest.TestCase):
def setUp(self):
self.lexer = lex.lex()
def test_simple_tokens(self):
data = io.StringIO("x = 10 + 20;")
self.lexer.input(data.read())
# Verificar os tokens um a um
tok = self.lexer.token()
self.assertEqual(tok.type, 'ID')
self.assertEqual(tok.value, 'x')
tok = self.lexer.token()
self.assertEqual(tok.type, 'EQUALS')
self.assertEqual(tok.value, '=')
# E assim por diante...
# Abordagem 1: Tabela de palavras reservadas
keywords = {
'if': 'IF',
'else': 'ELSE',
'while': 'WHILE',
'for': 'FOR',
'return': 'RETURN'
}
# Na função do token
def t_ID(t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
t.type = keywords.get(t.value, 'ID')
return t
# Controle de indentação no PLY
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
# Calcular indentação da próxima linha
t.lexer.begin('INDENT')
def t_INDENT_spaces(t):
r'[ \t]+'
# Contar espaços
indent = 0
for c in t.value:
if c == ' ':
indent += 1
elif c == '\t':
indent += 8 - (indent % 8)
# Comparar com nível anterior
if indent > t.lexer.indent_stack[-1]:
t.lexer.indent_stack.append(indent)
t.type = 'INDENT'
return t
# ...
# Exemplo simples de avaliador de expressões
def evaluate_expression(expr_str):
# Inicializar o lexer
lexer = lex.lex()
lexer.input(expr_str)
# Obter tokens
tokens = []
for tok in lexer:
tokens.append(tok)
# Analisar e avaliar...
result = parse_and_evaluate(tokens)
return result
# Uso em um programa maior
user_input = input("Digite uma expressão: ")
try:
result = evaluate_expression(user_input)
print(f"Resultado: {result}")
except Exception as e:
print(f"Erro na expressão: {e}")