O Que É Um Lex
O que é um lex
ou avaliador lexico
?
Lexical analyzer
ou lex
ou avaliador léxico
é um processo fundamental na arquitetura de qualquer interpretador ou compilador. Ele é responsável por analisar o codigo fonte
ou entrada de texto
iterando sobre cada caractere é gerando tokens
ou simbolos
que vão ser importante para os próximos passos de um compilador/interpretador.
Como escrever um lex ?
Exemplo: LexEstupido.js
class Token {
constructor(type, value) {
this.type = type;
this.value = value;
}
}
class Lexer {
constructor(code) {
this.code = code;
this.position = 0;
}
isWhitespace(char) {
return /\s/.test(char);
}
isDigit(char) {
return /\d/.test(char);
}
isAlpha(char) {
return /[a-zA-Z_]/.test(char);
}
getNextToken() {
while (this.position < this.code.length) {
const char = this.code[this.position];
if (this.isWhitespace(char)) {
this.position++;
continue;
}
switch (true) {
case this.isDigit(char):
return this.parseNumber();
case this.isAlpha(char):
return this.parseIdentifier();
case /[\+\-\*\/\(\)]/.test(char):
this.position++;
return new Token(char, char);
case char === '=':
this.position++;
return new Token('EQUALS', '=');
default:
console.error(`Erro léxico: Caractere inesperado '${char}' na posição ${this.position}`);
return null;
}
}
// Fim do código
return null;
}
parseNumber() {
let value = '';
while (this.position < this.code.length && this.isDigit(this.code[this.position])) {
value += this.code[this.position];
this.position++;
}
return new Token('NUMBER', parseInt(value, 10));
}
parseIdentifier() {
let value = '';
while (this.position < this.code.length && (this.isAlpha(this.code[this.position]) || this.isDigit(this.code[this.position]))) {
value += this.code[this.position];
this.position++;
}
return new Token('ID', value);
}
tokenize() {
const tokens = [];
let token;
while ((token = this.getNextToken()) !== null) {
tokens.push(token);
}
return tokens;
}
}
// Exemplo de uso
const codigoFonte = "x = 10 + 20 * (30 - 5)";
const lexer = new Lexer(codigoFonte);
const tokensResultantes = lexer.tokenize();
console.log(tokensResultantes);
Primeiramente, criamos um ‘Token’, uma estrutura que armazena a identidade de cada caractere. É importante observar que um ‘Token’ pode conter mais atributos do que os exemplificados aqui; meu exemplo é simplificado.
Em seguida, começamos com a classe que recebe o código no construtor. Posteriormente, o método ‘tokenize’ é implementado como o principal da classe, responsável por percorrer o código fonte. O método ‘getNextToken’ é encarregado de identificar o caractere atual e atribuí-lo a um ‘Token’. Os demais métodos servem apenas como validadores de strings. Ao final, o vetor de ‘Tokens’ é retornado.”