• Nenhum resultado encontrado

An´ alise lexical

No documento Ricardo Silveira Moreira (páginas 36-41)

2.3 Ferramentas an´ alise est´ atica de c´ odigo

2.3.1 An´ alise lexical

A an´alise lexical tem como objectivo definir tokens e traduzir o c´odigo num conjunto de instˆancias desses tokens. Em compiladores estas instˆancias tˆem o nome de lexemes e a identifica¸c˜ao dos tokens ´e feita recorrendo a express˜oes regulares.

Listing 2.1: C´odigo de exemplo

<%

’’Vai buscar o nome a query string ao parametro name

name = request.queryString["name"]

’’Isto vai imprimir para o ecra o name retirado do url

response.write name %>

Na analise lexical todas as linhas em branco e coment´arios no bloco de c´odigo 2.1 s˜ao ignorados. O foco desta an´alise, neste caso, ´e apenas o que est´a no bloco de

Cap´ıtulo 2. Contexto e trabalho relacionado 19

c´odigo 2.2.

Listing 2.2: C´odigo de exemplo sem coment´arios

<%

name = request.queryString["name"] response.write name

%>

Aplicando os padr˜oes dos tokens, s˜ao extra´ıdos v´arios lexemes que v˜ao ser colo- cados na tabela de s´ımbolos.

Tipicamente existem em todas as linguagens palavras reservadas, i.e., keywords, que n˜ao podem ser utilizadas como vari´aveis, nomes de instˆancias ou classes, como ´e o caso de if, else, true, f alse, int entre outros. Nestas palavras reservadas n˜ao existem instˆancias e portanto a descri¸c˜ao do token ´e o lexemme em si.

Temos ainda os literais que s˜ao aquilo a que se pode chamar de strings e que est˜ao entre “ ” . Finalmente, temos ainda os lexemes que s˜ao guardados em tabelas de s´ımbolos, juntamente com alguns dados como a linha e/ou a coluna onde apareceu pela primeira vez e ainda outro tipo de informa¸c˜ao.

Do bloco de c´odigo 2.2 podemos ent˜ao extrair os seguintes tokens e lexemmes; ID(name,1) - Lexemme = - Token ID(request,2) - Lexemme . - Token ID(queryString,3) - Lexemme ( - Token LITERAL(”name”) - Lexemme ) - Token ID(response,4) - Lexemme . - Token ID(write,5) - Lexemme ID(name,1) - Lexemme

A tabela de s´ımbolos que extra´ımos desta an´alise est´a representada na tabela abaixo Lexemme Position name 1 request 2 queryString 3 response 4 write 5

Tabela 2.1: Tabela de s´ımbolos

Nesta fase de an´alise lexical ´e interessante mencionar a ferramenta flex. Esta ferramenta permite especificar padr˜oes atrav´es de express˜oes regulares e escrever

c´odigo que vai ser executado quando uma express˜ao ´e reconhecida. Tipicamente a sua ac¸c˜ao ´e retornar um token para uma ferramenta de parsing.

Express˜oes regulares

A maneira mais f´acil de reconhecer padr˜oes ´e atrav´es de express˜oes regulares. Ex- press˜oes regulares s˜ao um conjunto de anota¸c˜oes constru´ıdas a partir de operadores de concatena¸c˜ao, fecho e uni˜ao, assim como tokens que descrevem alfabetos (con- juntos de um ou mais s´ımbolos). A grande vantagem das express˜oes regulares ´e a capacidade de poderem descrever qualquer linguagem que pode ser constru´ıda aplicando os operadores aos s´ımbolos de um alfabeto.

Um alfabeto no contexto de express˜oes regulares ´e definido como um conjunto finito de s´ımbolos, por exemplo o conjunto {0,1} pode ser definido como o alfabeto bin´ario.

O exemplo mais simples numa linguagem de programa¸c˜ao ´e a express˜ao regular que descreve um identificador em linguagem c, neste caso ´e [ a-zA-Z][ a-ZA-Z0- 9]{0,31}.

Esta express˜ao regular ´e capaz de identificar qualquer conjunto de s´ımbolos que comece com um underscore ou por uma letra mai´uscula ou min´uscula e que seja seguida de uma combina¸c˜ao de underscores, letras mai´usculas ou min´usculas ou n´umeros que podem ter entre zero a trinta e um s´ımbolos. Esta express˜ao regular serviria para identificar ent˜ao express˜oes no c´odigo fonte como lexemmes de tokens do tipo identificadores.

A grande vantagem das express˜oes regulares ´e serem simplific´aveis utilizando os conceitos de alfabetos.

Por exemplo, se definirmos o alfabeto letras como o conjunto [a-zA-Z ] e o alfabeto numeros como o conjunto [0-9], podemos reescrever a regra [ a-zA-Z][ a- zA-Z0-9]{0,31} como (letras )(letras |numeros){0,31}.

´

E interessante tamb´em mencionar aqui m´aquinas de estado ou FSA(finite state

automaton), atrav´es da qual ´e poss´ıvel descrever visualmente o comportamento de uma express˜ao regular. Nas m´aquinas de estado temos estados que s˜ao representados como c´ırculos, transi¸c˜oes que s˜ao representados como setas e descrevem ac¸c˜oes me- diante uma condi¸c˜ao. A express˜ao de cima pode ser traduzida na seguinte m´aquina de estado:

Cap´ıtulo 2. Contexto e trabalho relacionado 21

A leitura da m´aquina de estados da Figura 2.3 ´e feita da seguinte maneira: quando ´e reconhecido um caractere que esteja compreendido no alfabeto letras ´e feita a transi¸c˜ao para o estado 1, quando deste ´e reconhecido qualquer caractere que esteja compreendido no alfabeto letras ou no alfabeto numeros, a m´aquina permanece no estado 1 at´e que identifique qualquer outro s´ımbolo (representado pelo alfabeto other ). Nesta fase, termina o reconhecimento de um identificador e pode-se chegar a um estado final representado por um c´ırculo, com um c´ırculo mais pequeno concˆentrico. Este t´opico ser´a mais aprofundado na sec¸c˜ao seguinte.

M´aquinas de estado

O reconhecimento interno de ferramentas de an´alise lexical ´e feito a partir destas m´aquinas de estado. Uma m´aquina de estado ´e o que se chama um aceptor de uma linguagem regular. ´E um modelo matem´atico de um computador que potencialmente ´e capaz de reconhecer qualquer programa, dentro das quais podemos distinguir dois tipos [42]:

• Aut´omato finito n˜ao determin´ıstica (AFND) - n˜ao tˆem restri¸c˜oes quanto aos s´ımbolos nas transi¸c˜oes podendo ter v´arias transi¸c˜oes com o mesmo s´ımbolo a partir do mesmo estado. Podem ainda ter transi¸c˜oes , que representa um caracter vazio. ´E destas mesmas labels em transi¸c˜oes diferentes que surge o n˜ao determinismo porque do mesmo estado com o mesmo s´ımbolo pode-se ir para estados diferentes.

• Aut´omato finito determinista (DFA),- n˜ao podem ter o mesmo s´ımbolo em diferentes transi¸c˜oes a partir de um mesmo estado.

Os programas que s˜ao capazes de reconhecer express˜oes regulares converter in- ternamente a express˜ao regular para uma destas m´aquinas de estado, e de seguida alimentam a m´aquina com a string que tˆem a express˜ao regular a ser reconhecida.

Existem outras variantes destas como o Posix AFND. A grande diferen¸ca desta para a AFND ´e que no Posix AFND ´e feito backtracking (voltar para um estado anterior para testar uma transi¸c˜ao diferente) at´e ser descoberta a maior express˜ao poss´ıvel. Existe tamb´em uma variante para o DFA, e existem ainda h´ıbridos que tentam fazer os dois.

M´aquinas de estado n˜ao deterministas (AFND)

Uma m´aquina de estados n˜ao determinista consiste num n´umero finito de estados, um alfabeto que ´e reconhec´ıvel pela m´aquina, um fun¸c˜ao de transi¸c˜ao para cada estado (que permite atribuir para cada s´ımbolo um estado seguinte), um estado inicial e um conjunto de estados finais.

Para desenhar uma m´aquina de estado capaz de reconhecer a express˜ao regu- lar, ”abc(a|b|c)*a” que corresponde a qualquer express˜ao que come¸ca com ”abc” e termina com ”a” e que pode ter no meio uma combina¸c˜ao qualquer de a,b ou c, a m´aquina de estados correspondente seria:

Figura 2.4: M´aquina de estados que reconhece a express˜ao abc(a|b|c)*a

Se considerarmos que as transi¸c˜oes  na figura 2.4 podem ser ignoradas, a m´aquina de estado acima ´e trivial. Podemos simplificar a vers˜ao acima

Figura 2.5: M´aquina de estados simplificada que reconhece a express˜ao abc(a|b|c)*a

Apartir desta m´aquina de estados se fizermos passar qualquer express˜ao na forma ”abc(a|b|c)*a”, como abcbbbbccccaaaaaaaa, abcbbaabaa entre outras, chegamos sempre a um estado final 13 na m´aquina de estados da figura 2.4 ou 4 na m´aquina de estados da figura 2.5, o que indica que a express˜ao dada ´e reconhecida pela m´aquina de estados, dado que podemos chegar a um estado de aceita¸c˜ao.

M´aquinas de estados deterministas (DFA)

Numa m´aquina de estados determinista, cada s´ımbolo est´a associada apenas a uma transi¸c˜ao e n˜ao existem transi¸c˜oes associadas ao s´ımbolo . Para se desenhar uma m´aquina de estados deterministas parte-se sempre de uma m´aquina de estados n˜ao deterministas. A mesma express˜ao regular referida em 2.3.1, representada neste tipo de m´aquina de estados, daria origem `a m´aquina de estados mostrada na figura 2.6.

A convers˜ao para este tipo ´e tamb´em bastante pesada. A ideia base de convers˜ao ´e calcular para cada estado a transi¸c˜ao poss´ıvel associada a cada s´ımbolo e perceber quais destas d˜ao origens a estados novos. Computacionalmente este processo ´e muito trabalhoso porque de cada vez que surge um estado novo ´e preciso re-calcular as transi¸c˜oes para cada s´ımbolo e perceber se o estado a que d´a origem j´a existe ou n˜ao. Se n˜ao existir ´e necess´ario continuar a calcular.

Cap´ıtulo 2. Contexto e trabalho relacionado 23

Figura 2.6: M´aquina de estados que reconhece a express˜ao abc(a|b|c)*a

Compara¸c˜ao

A grande vantagem das DFA ´e, dado que para cada estado existe apenas uma transi¸c˜ao para cada s´ımbolo, um estado de aceita¸c˜ao (final) pode ser alcan¸cado muito mais rapidamente. Por outro lado, em compara¸c˜ao com as AFND, onde ´e poss´ıvel ter v´arias transi¸c˜oes de um estado com o mesmo s´ımbolo, nestas pode vir a ser necess´ario fazer backtracking.

Outra desvantagem dos DFA ´e o espa¸co que ocupam. Qualquer AFND para uma linguagem Ln deve ter pelo menos 2n estados [16]. Isto pode ser um problema

se existirem alfabetos com muitos s´ımbolos e express˜oes regulares muito complexas, porque pode ser necess´ario utilizar espa¸co em disco se o espa¸co em mem´oria n˜ao for suficiente para armazenar a tabela de transi¸c˜ao.

Isto ´e uma das vantagens de utilizar as bibliotecas de express˜oes regulares do C# que fazem a tradu¸c˜ao da express˜ao regular para AFND e permitem a pr´e compila¸c˜ao de express˜oes regulares, convers˜ao do AFND para DFA. Isto faz com que a m´aquina de estados resultante seja mantida em mem´oria durante o tempo de execu¸c˜ao e n˜ao seja necess´ario estar sempre a reconstruir a mesma [24][25].

Algumas ferramentas de an´alise est´atica de c´odigo terminam a sua an´alise nesta fase. Ferramentas como o RATS, FLAWFINDER, YASCAA entre outras, tˆem al- gumas fun¸c˜oes identificadas como potencialmente vulner´aveis a ataques e quando as identificam recorrendo simplesmente a an´alise lexical, lan¸cam alertas.

No documento Ricardo Silveira Moreira (páginas 36-41)

Documentos relacionados