quinta-feira, 20 de fevereiro de 2014

7 - Declarando Funções e Comandos

Olá pessoal, depois de um bom tempo sem postar aqui no blog, resolvi retornar os posts sobre AutoLISP. Continuarei os conceitos básicos sobre AutoLISP, para depois entrar em temas mais avançados. Neste post irei explicar como se declara funções e comandos em AutoLISP. 


- Declarando Funções

Dentro de uma função, podemos ter uma sequencia de comandos e inclusive podemos chamar outras funções declaradas pelo programador. Quando se chama uma função, podemos querer passar para ela, determinados valores, isto pode ser feito facilmente por parâmetros, que são variáveis que servem de ligação entre as funções.
Abaixo é mostrado a sintaxe de como declarar uma função:

(defun NOME_FUNÇÃO (PARÂMETROS / VARIÁVEIS_LOCAIS)
           LISTA_DE_COMANDOS_DA_FUNÇÃO
)

, onde NOME_FUNÇÃO é um nome para a função declarada, sendo que este nome deve ser único, ou seja, não podemos ter outras funções com o mesmo nome, pois neste caso, apenas a última função carregada que será a válida. E além disso, não podemos utilizar palavras que já são nomes de comandos no AutoCAD, como line, circle, insert, etc; pois, senão as funções declaradas pelo programador não serão chamadas.
Não se deve também, utilizar palavras chaves da linguagem, como car, while, defun, if, etc;  
Basicamente, qualquer letra, número ou caractere pode ser utilizado como nome da função, sendo que não existe distinção entre maiúsculas ou minúsculas, então os seguintes nomes: funcao1, FUNCAO1, Funcao1, FuNcAo1, são consideradas a mesma coisa.
Como forma de boa programação, recomenda-se utilizar nomes chaves que resumem o que a função faz, para que toda vez que o programador ver o nome, ele já saiba do que se trata a função.

PARÂMETROS são as variáveis passadas para a função, podemos passar qualquer quantidade necessária de parâmetros, sendo que cada parâmetro pode ser um átomo, uma lista ou até mesmo uma função declarada. 
Assim, podemos passar por exemplo, os seguintes parâmetros: um número inteiro, uma string e outro com uma lista, sendo que esta ordem e a quantidade de parâmetros, deve ser respeitada na chamada da função, sendo de total responsabilidade do programador. Se o número de parâmetros passados for incorreto, ocorrerá um erro em tempo de execução do programa, porém se o tipo de parâmetro for incorreto, este pode causar diversos tipos de erros ou dependendo do código, não causar nenhum erro!!!
Para quem conhece outras linguagens de programação, deve estar perguntando se o parâmetro é passado por valor ou referência, a resposta é que só se pode passar parâmetros por valor em lisp, ou seja, se a variável passada tiver o valor modificado dentro da função que foi chamada, esta mudança de valor, não irá ser "sentida" em nenhuma variável da função que fez a chamada. No final deste post, veremos mais sobre isto.

VARIÁVEIS_LOCAIS são as variáveis que terão seu valor válido apenas dentro da função e também para todas as funções que ela chamar. Para se ter uma ideia, toda variável declarada em AutoLISP é considerada Global, ou seja, qualquer função pode ter acesso a este valor, indo mais além, uma variável global declarada no AutoCAD, só deixará de existir na memória, apenas quando o desenho corrente do AutoCAD for fechado. Para evitar que este valor fique na memória, devemos adicionar o nome da variável no campo das VARIÁVEIS_LOCAIS. Toda variável local, é inicializada com o valor nil.

LISTA_DE_COMANDOS_DA_FUNÇÃO é o corpo do programa, onde irá conter toda a lógica e o fluxo da função, como por exemplo contas aritméticas, avaliações booleanas, a iteração com o AutoCAD, chamadas para outras funções, etc.

Exemplos de declaração de função:

- Exemplo1: A função abaixo tem uma variável local chamada var, que recebe o valor 0:
(defun MinhaFuncao ( / var)
(setq var 0)
)

- Exemplo2: A função abaixo recebe dois parâmetros e faz uma somatória dos valores passados, guardando o resultado numa variável local:
(defun somaParametros (valor1 valor2 / resultado)
    (setq resultado (+ valor1 valor2 ))
)

- Exemplo3: A função abaixo,  não faz nada:
(defun funcaoNil ( / )
     nil
)



- Toda função declarada retorna um valor


Isto é uma regra geral quando se declara funções em AutoLISP, na verdade tudo que é avaliado em lisp deve retornar um valor, sendo assim, as funções também estão nesta regra. O valor retornado pela função sempre será a última avaliação feita de dentro da função, nos exemplos anteriores, a função do exemplo1, "MinhaFuncao" vai retornar o valor 0. A função do exemplo2, "somaParametros" vai retornar o valor setado na variável "resultado", que será a soma dos dois parâmetros. E a função do exemplo3, "funcaoNil" retorna sempre o valor do átomo nil.


- Chamando funções declaradas


Para chamar uma função que foi declarada é muito simples, basta escrever o nome da função dentro de parênteses, se a função tiver parâmetros, deve-se escrever logo após o nome da função os valores ou nomes das variáveis que serão passados o valor. Como exemplo, vamos voltar no caso dos três exemplos declarados anteriormente:
- O exemplo1, a chamada da função será:
(MinhaFuncao)  

- O exemplo2, na chamada da função devemos passar dois parâmetros numéricos:
(somaParametros 1 2)        ; obs: esta função retorna o valor 3.


Se tivermos duas variáveis com números, podemos fazer assim:
(setq numero1 10)
(setq numero2 15)
(somaParametros numero1 numero2)        ; obs: esta função retorna o valor 25.

- O exemplo3, a chamado da função será:
(funcaoNil)

OBS: podemos combinar o resultado gerado por uma função, setando o diretamente numa variável, como mostrado abaixo, utilizando a função do exemplo2: 
(setq valor (somaParametros 2 3))   ; assim a variável "valor", receberá o valor de 5.



- Declarando comandos para serem executados no AutoCAD

Para declarar um comando no AutoCAD, devemos declarar uma função como explicado anteriormente, porém com uma diferença na hora de declarar o NOME_FUNÇÃO. O nome da função deve conter o escrito "c:" (a letra c seguida de dois pontos, sem as aspas), antes do nome da função.
Exemplo:
- Declarando um comando com o nome: "MeuComando":
(defun c:MeuComando ( / )
    ....
)

- Chamando o comando (não precisa de parênteses):
MeuComando

obs: deve-se evitar utilizar parâmetros quando se cria comandos, pois senão a chamada do comando deverá ter o uso de parênteses, como mostrado no exemplo abaixo:
- Declarando comando chamado "MeuComando2":
(defun c:MeuComando2 (parametro1 / )
    ....
)

- Chamando o comando (precisa de parênteses):
(c:MeuComando2 10)



- Variável Global/Local, e parâmetros passados por valor


A resposta desta questões, depende basicamente se a variável for declarada localmente ou não. 
Abaixo veremos alguns casos:

- Caso1, variável local que se torna global para as funções chamadas (situação não recomendada):
 Digamos que temos duas funções chamadas Pai e Filho, e a função Pai tem um parâmetro local chamado "idade", e a função Filho utiliza também uma variável chamada "idade", mas que não foi declarada localmente, e nem passada como parâmetro, abaixo podemos ver as declarações das funções:

(defun c:Pai ( / idade)
  
  (setq idade 40)
  (alert (itoa idade))
  (Filho)
  (alert (itoa idade))
)

(defun Filho( / )
  (setq idade 15)
)

obs: no comando (alert (itoa idade)) , a chamada itoa converte o número para string, e alert exibe uma janela no AutoCAD com o valor da string, estas funções serão detalhadas melhores em futuros posts.

Valores exibidos após a chamada da função Pai:
- 40
- 15

Pelo resultado acima, podemos ver, que a variável idade é considerada global para a função Filho, pois esta pode modificar o seu valor, assim, quando se declara uma variável como local numa função, todas as funções chamadas após, poderão ter acesso de leitura e escrita na variável.


- Caso2, variável local que é local apenas na própria função:
Voltando nas duas funções declaradas anteriormente, para que a variável idade não se torne global para as funções chamadas, devemos em cada função chamada declarar como local a variável. Abaixo, um exemplo mostrando este caso:

(defun c:Pai ( / idade)
  
  (setq idade 40)
  (alert (itoa idade))
  (Filho)
  (alert (itoa idade))
)

(defun Filho( / idade)
  (setq idade 15)
)

Valores exibidos após a chamada da função Pai:
- 40
- 40

Assim, nesta situação temos como se tivéssemos duas variáveis diferentes nas duas funções, e qualquer valor declarado na variável idade da função Filho, não influencia na variável da função Pai.


- Caso3, passando parâmetros por valor:
Neste caso, criamos um parâmetro na função Filho com o mesmo nome da variável idade, e na chamada da função Filho, passamos justamente a variável idade. Foi colocado para se exibir o valor de idade na função filho assim como na função Pai, como pode ser visto nas funções abaixo:

(defun c:Pai ( / idade)
  
  (setq idade 40)
  (alert (itoa idade))
  (Filho idade)
  (alert (itoa idade))
)

(defun Filho(idade / )

        (alert (itoa idade))
        (setq idade 15)
        (alert (itoa idade))
)

Valores exibidos após a chamada da função Pai:
- 40
- 40
- 15
- 40

O que podemos notar neste caso, é que sempre que passamos um parâmetro, este será por valor, mesmo se o parâmetro tiver o mesmo nome usado na função Pai. O valor chegou na função filho com o valor de 40, este modificou o valor para 15, mas quando voltamos pra função Pai, o valor não foi modificado, continuando com o valor 40. 



O que podemos verificar com este post, é que em lisp, tudo é uma função, exceto os átomos (nil e T), assim temos como exemplo as funções: list, if, setq, +, =, >, etc.
No próximo post, eu irei falar sobre as Funções de conversão, sendo que uma delas foi mostrada neste post, a função itoa, que converte um inteiro numa string, farei uma explicação dela e das demais funções.

sexta-feira, 1 de junho de 2012

6 - Funções de repetição

Olá pessoal, neste post irei falar sobre as funções de repetição da linguagem AutoLisp. A partir dos comandos de repetição podemos fazer com que um determinado trecho de código possa ser repetido. Neste post, eu irei falar dos comandos de repetição WHILE e REPEAT.


- while

O comando de repetição while do AutoLisp permite que um trecho de código seja repetido (loop), enquanto uma expressão lógica for verdadeira. Se esta expressão nunca se tornar falsa, o programa entra no que chamamos em programação de "Loop Infinito", ou seja, um trecho de código será repetido infinitamente. Assim o programador deve estabelecer dentro do trecho a ser repetido, algum mecanismo que torne em algum momento, falso o resultado da expressão avaliada pelo while.
A sintaxe do comando while é a seguinte:

(while (EXPRESSÃO BOOLEANA)
          (COMANDO 1)
          (COMANDO 2)
          (COMANDO 3)
          ...
          (COMANDO N)
)


Exemplos:

- O exemplo abaixo, mostra um loop que nunca será feito, pois a expressão booleana avaliada pelo while, possui sempre o valor nil (falso). Assim, o comando  (princ "loop"), nunca será executado.

(while nil
          (princ "loop")
)


- No exemplo abaixo, é declarado uma variável chamada contador com o valor 0. Em seguida a função while avalia a expressão booleana (< contador 5). Assim, enquanto o valor da variável contador for menor do que 5, o comando que incrementa uma unidade na variável contador é executado:  (setq contador (+ contador 1)).
Quando a variável atingir o valor 5, a expressão booleana irá retornar falso, e o fluxo de execução do programa, sairá do loop.

(setq contador 0)
(while (< contador 5)
          (setq contador (+ contador 1))
)

O loop acima, será executado cinco vezes, parando quando a variável contador atingir o valor 5 e for avaliado pela expressão booleana.


- No exemplo abaixo, é declarado uma variável chamada repetir com o valor T. Em seguida a função while avalia a expressão booleana, que no caso, é verdadeiro (contéudo da variável repetir), assim a função executa os três comandos declarados dentro do while.
O terceiro comando executado de dentro do while, declara a variável repetir como nil, assim, logo em seguida, quando o comando while avalia a expressão boolena novamente, esta retornará falso, o que faz com que o fluxo de execução do programa saia do while.

(setq repetir T)
(while repetir
          (print "linha1")
          (print "linha2")
          (setq repetir nil)
)

O loop acima, será executado apena uma vez, pois após a primeira iteração do loop, a variável repetir assume o valor falso (nil).




- repeat

O comando repeat é bem simples, com ele é possível executar um trecho de código por uma quantidade estabelecida de vezes. A sintaxe do comando repeat é a seguinte:


(repeat INTEIRO
            (COMANDO 1)
            (COMANDO 2)
            (COMANDO 3)
             ...
            (COMANDO N)

)


Na sintaxe acima, o campo INTEIRO deve ser um número inteiro positivo e diferente de zero para que a função repeat execute a sua sequencia de comandos.


Exemplos:

- O código abaixo, repete por duas vezes o comando print, com isto é impresso por duas vezes a palavra "oi" na linha de comando do autocad:

(repeat 2
            (print "oi")
)


- O código abaixo, estabelece inicialmente algumas variáveis, e em seguida é repetido o código contido na função repeat, por dez vezes, o que faz com que as variáveis valor1 e valor2 tenham seus valores modicados a cada passada.

(setq valor1 0)
(setq valor2 0)
(setq quantidade 10)
(repeat quantidade
             (setq valor1 (+ valor1 1))
             (setq valor2 (- valor2 1))
)


Pessoal, isto é tudo! No próximo post, irei falar sobre como declarar funções em AutoLisp, e como criar funções que podem ser usadas para criar comandos no AutoCAD. Funções são usadas para criar os programas em AutoLisp e podem ser salvas e executadas posteriormente pelo usuário.

quarta-feira, 30 de maio de 2012

5 - Funções condicionais

Olá pessoal, neste post irei falar sobre as funções condicionais que a linguagem AutoLisp possui. Estas funções são bem importantes em linguagens de programação, para quem não sabe, com as funções condicionais, podemos fazer com que um trecho de código seja ou não executado. Neste post, eu irei falar dos comandos condicionais IF e COND.



- IF (SE)


O comando condicional if, avalia uma expressão booleana, que ao ser verdadeira permite a execução de um determinado trecho de código. Este comando pode ter um "SENÃO", ou seja, se a expressão booleana não for verdadeira, é executado um trecho de código diferente do trecho que foi atribuído a ser executado quando verdadeiro. O trecho de código que deve ser executado quando se avalia o if, deve estar dentro do parentes do if, assim a sintaxe do comando if é a seguinte:

(if (EXPRESSÃO BOOLEANA)
     (COMANDO A SER EXECUTADO, QUANDO A EXPRESSÃO BOOLEANA É VERDADEIRA)
     (COMANDO A SER EXECUTADO, QUANDO A EXPRESSÃO BOOLEANA É FALSA)
)

A sintaxe apresentada acima, executa apenas um comando se a expressão for verdadeira, e apenas um comando se ela for falsa. Se o programador quiser, que seja executado mais de um comando, é necessário utilizar de um "truque" que é a utilização da expressão progn. Abaixo, podemos ver a sintaxe do comando if mesclado com o progn:

(if (EXPRESSÃO BOOLEANA)
     (progn
          (COMANDO 1 - EXPRESSÃO BOOLEANA É VERDADEIRA)
          (COMANDO 2 - EXPRESSÃO BOOLEANA É VERDADEIRA)
          (COMANDO 3 - EXPRESSÃO BOOLEANA É VERDADEIRA)
          ...
          (COMANDO N - EXPRESSÃO BOOLEANA É VERDADEIRA)
     )  
     (progn
          (COMANDO 1 - EXPRESSÃO BOOLEANA É FALSA)
          (COMANDO 2 - EXPRESSÃO BOOLEANA É  FALSA )
          (COMANDO 3 - EXPRESSÃO BOOLEANA É  FALSA )
          ...
          (COMANDO N - EXPRESSÃO BOOLEANA É  FALSA )
     )  

)


Exemplos:
- (if T (setq x 10) (setq x 20)) , a variável x, sempre receberá o valor 10, pois a expressão sempre é verdadeira.
- (if (= teste 0) (setq x 10)) , se a variável teste for igual a 0, então a variável x receberá o valor 10, caso contrário, nada é executado.
- (if (= teste 0) (setq x 10) (setq x 20)) , se a variável teste for igual a 0, então a variável x receberá o valor 10, caso contrário, receberá o valor 20.
- (if (= teste 0) (progn (setq x 10) (setq y 5)) (setq x 20)) , se a variável teste for igual a 0, então a variável x receberá o valor 10 e a variável y o valor 5, caso contrário, x receberá o valor 20.
- (if (= teste 0) (progn (setq x 10) (setq y 5)) (progn (setq x 20) (setq y 5))) , se a variável teste for igual a 0, então a variável x receberá o valor 10 e a variável y o valor 5, caso contrário, x receberá o valor 20 e y o 5.



- COND


O comando condicional cond, testa uma série de expressões, e executa a primeira que for verdadeira. Este comando é muito parecido com o switch de algumas linguagens de programação como C++. A sintaxe em autolisp para utilizar o comando cond é a seguinte:

(cond ((EXPRESSÃO BOOLEANA 1) (COMANDOS 1))
          ((EXPRESSÃO BOOLEANA 2) (COMANDOS 2))
          ((EXPRESSÃO BOOLEANA 3) (COMANDOS 3))
          ...
          ((EXPRESSÃO BOOLEANA N) (COMANDOS N))
          (T (COMANDOS DEFAULT)) 
)

Pela sintaxe acima, primeiro é verificado a expressão boolena 1, se ela for verdadeira é executado somente os comandos contidos em "comandos 1". Se ela for falsa, então o fluxo do programa avalia a expressão booleana 2 da mesma forma, se ela for verdadeira é executado somente os comandos contidos em "comandos 2", e se for falsa, passa para a próxima expressão boolena se esta existir. 
A última linha mostrada na sintaxe " (T (COMANDOS DEFAULT)) ", mostra uma forma de criar uma expressão opcional do cond, caso o programador precise de um comando padrão (default), que será executado sempre que todas as expressões booleanas anteriores forem falsas.


Exemplos: 

- É declarado a variável numero com o valor 3. Em seguida verifica-se se o número é igual a zero, maior que zero ou menor do que zero através da função cond. Neste exemplo não foi utilizado um comando default. (obs: o comando princ imprime uma string na linha de comando do autocad):
(setq numero 3)
(cond ((= numero 0) (princ "O número é 0"))
          ((> numero 0) (princ "O número é maior do que 0"))
          ((< numero 0) (princ "O número é menor do que 0"))
)

No exemplo acima, será executado a segunda expressão boolena, pois a variável numero é maior do que zero, assim é impresso na linha de comando que o número é maior do que 0.


- No exemplo abaixo, é declarado a variável estado com a string "Bahia", em seguida através da função cond é verificado se uma das expressões é verdadeira, caso alguma seja, é executado os comandos referentes a expressão que for verdadeira:

(setq estado "Bahia")
(cond   ((= estado "Minas Gerais") 
(setq ddd 31) 
(setq capital "Belo Horizonte")
)
((= estado "São Paulo") 
(setq ddd 11) 
(setq capital "São Paulo")
)
((= estado "Rio de Janeiro") 
(setq ddd 21) 
(setq capital "Rio de Janeiro")
)
(T
(princ "Estado não cadastrado!")
)
)

No exemplo acima, será executado a última expressão, que é a default, pois nenhuma das expressão avaliadas anteriormente é verdadeira.


No próximo post, eu irei falar sobre as funções de repetição. Até lá, pessoal!



sábado, 5 de maio de 2012

4 - Operadores lógicos e de comparação

olá pessoal, neste post irei falar um pouco sobre operadores lógicos e operadores de comparação, é um assunto bem simples, mas muito importante.



Operadores de comparação

Assim como em outras linguagens, o AutoLISP permite fazer comparações entre duas entidades, como por exemplo verificar se o conteúdo de duas variáveis são iguais. Toda expressão em lisp retorna um valor, no caso da comparação, existe dois resultados diferentes possíveis: T (verdadeiro) ou nil (falso). Uma expressão de comparação em AutoLisp é sempre composta do comparador, seguidos de dois argumentos. Estes argumentos devem ser átomos, sendo que alguns comparadores podem comparar também listas.

OBS: quando se compara duas strings, ele leva em consideração a ordem lexicográfica, que é análoga à ordem das palavras em um dicionário. Esta ordem  lexicográfica se baseia na ordenação dos caracteres estabelecida na tabela ISO8859-1 (http://pt.wikipedia.org/wiki/ISO_8859-1).
Assim, quando se compara duas strings s e t, procura-se a primeira posição, digamos k, em que as duas strings diferem. Se s[k] vem antes de t[k] na tabela ISO então s é lexicograficamente menor que t.

Abaixo será listado os comparadores mais importantes em AutoLisp, seguidos de sua descrição e exemplos:

  • = (IGUAL)
    • Descrição: compara se dois átomos (ou expressões que retornam átomos) são iguais.
    • Exemplos: 
      • (= 10 10)           , retorna T;
      • (= 1 2)           , retorna nil;
      • (setq a 11)          (setq b 11)          (= a b)           , retorna T
      • (= "autolisp" "autolisp")           , retorna T;
      • (= "brasil" "autolisp")           , retorna nil;
      • (= "autoCAD" "autocad")           , retorna nil;
      • (= 10 (- 20 10))            , retorna T;
    • BUG?
      • As duas expressões abaixo, deveriam retornar ambas T, porém isto não ocorre:
        • (= 6.0 (- 8.1 2.1))           , retorna T;
        • (= 6.0 (- 8.2 2.2))           , retorna nil;
      • Não encontrei uma explicação oficial sobre este bug, mas é bem provável que esteja ocorrendo um erro de arredondamento, pois no teste abaixo verificamos que existe uma influência do número de casas:
        • (= 5.999999999999999 (- 8.2 2.2))           , retorna T;

  • /= (DIFERENTE)
    • Descrição: compara se dois átomos (ou expressões que retornam átomos) são diferentes.
    • Exemplos: 
      • (/= 10 10)           , retorna nil;
      • (/= 1 2)           , retorna T;
      • (setq a 11)          (setq b 11)          (/= a b)           , retorna nil;
      • (/= "autolisp" "autolisp")           , retorna nil;
      • (/= "brasil" "autolisp")           , retorna T;  
      • (/= "autoCAD" "autocad")           , retorna T;
      • (/= 10 (- 20 10))            , retorna nil;

  • > (MAIOR)
    • Descrição: compara se o primeiro argumento é maior do que o segundo.
    • Exemplos: 
      • (> 10 10)           , retorna nil;
      • (> 1 2)           , retorna nil;
      • (> 5 1)           , retorna T;
      • (setq a 55)          (setq b 54)          (> a b)           , retorna T;
      • (> "autolisp" "autolisp")           , retorna nil;
      • (> "brasil" "autolisp")           , retorna T;  
      • (> "autolisp" "brasil")           , retorna nil;   
      • (> "autoCAD" "autocad")           , retorna nil
      • (> (+ 1 2) (- 1 2))            , retorna T;
      • (> (/ 10 2) 5)            , retorna nil;  

  • < (MENOR)
    • Descrição: compara se o primeiro argumento é menor do que o segundo.
    • Exemplos: 
      • (< 10 10)           , retorna nil;
      • (< 1 2)           , retorna T;
      • (< 5 1)           , retorna nil;
      • (setq a 55)          (setq b 54)          (< a b)           , retorna nil;
      • (< "autolisp" "autolisp")           , retorna nil;
      • (< "brasil" "autolisp")           , retorna nil;  
      • (< "autolisp" "brasil")           , retorna T;  
      • (< "autoCAD" "autocad")           , retorna T;  
      • (< (+ 1 2) (- 1 2))            , retorna nil;
      • (< (/ 10 2) 5)            , retorna nil;  

  • >= (MAIOR  OU IGUAL)
    • Descrição: compara se o primeiro argumento é maior ou igual ao segundo.
    • Exemplos: 
      • (>= 10 10)           , retorna T;
      • (>= 1 2)           , retorna nil;
      • (>= 5 1)           , retorna T;
      • (setq a 55)          (setq b 54)          (>= a b)           , retorna T;
      • (>= "autolisp" "autolisp")           , retorna T;
      • (>= "brasil" "autolisp")           , retorna T;  
      • (>= "autolisp" "brasil")           , retorna nil;  
      • (>= "autoCAD" "autocad")           , retorna nil;   
      • (>= (/ 10 2) 5)            , retorna T;  

  • <= (MENOR OU IGUAL)
    • Descrição: compara se o primeiro argumento é menor ou igual ao segundo.
    • Exemplos: 
      • (<= 10 10)           , retorna T;
      • (<= 1 2)           , retorna T;
      • (<= 5 1)           , retorna nil;
      • (setq a 55)          (setq b 54)          (<= a b)           , retorna nil;
      • (<= "autolisp" "autolisp")           , retorna nil;
      • (<= "brasil" "autolisp")           , retorna nil;  
      • (<= "autolisp" "brasil")           , retorna T;  
      • (<= "autoCAD" "autocad")           , retorna T;   
      • (<= (/ 10 2) 5)             , retorna T;  

  • eq (IDÊNTICO)
    • Descrição: compara se os argumentos são derivados um do outro (não compara listas).
    • OBS1: na grande maioria dos casos, o resultado será idêntico ao "=" (IGUAL), como é mostrado nos exemplos abaixo, que são os mesmos utiizados nos exemplos do "=", e que retornaram o mesmo resultado.
    • Exemplos: 
      • (eq 10 10)           , retorna T;
      • (eq 1 2)           , retorna nil;
      • (setq a 11)          (setq b 11)          (eq a b)           , retorna T
      • (eq "autolisp" "autolisp")           , retorna T;
      • (eq "brasil" "autolisp")           , retorna nil;
      • (eq "autoCAD" "autocad")           , retorna nil;
      • (eq 10 (- 20 10))            , retorna T;
    • OBS2: pesquisando na internet, por casos onde o "=" e o "eq" retornam valores diferentes, consegui achar uma situação em que eles se diferem. Quando se salva o nome de uma entidade desenhada, em duas variáveis diferentes, a comparação com o "=" retorna nil, e com "eq" retorna T. Como o código para este exemplo contém assuntos que ainda não expliquei, coloquei o código para este exemplo, ao final deste post, na seção extras.

  • equal (EQUIVALENTE)
    • Descrição: compara se os argumentos são equivalente (pode comparar listas)
    • Exemplos: 
      • (equal 10 10)           , retorna T;
      • (equal 1 2)           , retorna nil;
      • (equal 5 1)           , retorna nil;
      • (setq a 55)          (setq b 54)          (equal a b)           , retorna nil;
      • (equal "autolisp" "autolisp")           , retorna T;
      • (equal "brasil" "autolisp")           , retorna nil;  
      • (equal "autolisp" "brasil")           , retorna nil;  
      • (equal "autoCAD" "autocad")           , retorna nil;   
      • (equal (list 1 2 3) (list 1 2 3))           , retorna T;   
      • (equal (list 1 2) (list 2 1))           , retorna nil;  




Operadores lógicos

Com os operadores lógicos, podemos montar expressões booleanas, que ao serem avaliadas, retornam T (verdadeiro) ou nil (falso). Assim, com ajuda dos operadores de comparação, podemos montar expressões mais complexas. Os operadores lógicos disponíveis em AutoLISP são três: AND, OR e NOT
OBS: toda lista e todo átomo é considerado como T (verdadeiro), sendo que o único valor que é considerado nil (falso) é o próprio átomo nil.

  • AND (e)
    • Descrição: Operador lógico onde a resposta da operação é verdade (T) se ambas as variáveis de entrada forem verdade.
    • Exemplos: 
      • (and 10 10)           , retorna T;
      • (and 1 2)           , retorna T;
      • (setq a 55)          (setq b 54)          (and a b)           , retorna T;
      • (and "brasil" "autolisp")           , retorna T
      • (and (list 1 2) (list 2 1))           , retorna  T;  
      • (and (= (list 1 2)  (list 1 2)) (equal  (list 1 2)  (list 1 2)))            , retorna  nil
      • (and (> 2 0) (< -2 0))            , retorna  T;  
      • (and (= 1 1) (> 1 1))             , retorna  nil
      • (and (< 10 5) (> 10 20))              , retorna  nil
      • (and T nil)               , retorna nil
      • (and T)             , retorna T;  

  • OR (ou)
    • Descrição: Operador lógico onde a resposta da operação é verdade (T) se e somente se pelo menos uma das variáveis de entrada for verdade.
    • Exemplos: 
      • (or 10 10)           , retorna T;
      • (or 1 2)           , retorna T;
      • (setq a 55)          (setq b 54)          (or a b)           , retorna T;
      • (or "brasil" "autolisp")           , retorna T
      • (or (list 1 2) (list 2 1))           , retorna  T;  
      • (or (= (list 1 2)  (list 1 2)) (equal  (list 1 2)  (list 1 2)))            , retorna   T
      • (or (> 2 0) (< -2 0))            , retorna  T;  
      • (or (= 1 1) (> 1 1))             , retorna  T
      • (or (< 10 5) (> 10 20))              , retorna  nil
      • (or T nil)               , retorna T
      • (or T)             , retorna T;  

  • NOT (negação)
    • Descrição: Operador lógico que representa a negação (inverso) da variável atual. Se ela for verdade, torna-se falsa, e vice-versa.
    • OBS: deve avaliar um argumento, que pode ser uma expressão.
    • Exemplos: 
      • (not 10)           , retorna nil;
      • (setq a 55)          (setq b 54)          (not (or a b))           , retorna nil;
      • (not "autolisp")           , retorna nil
      • (not (list 1 2))           , retorna nil;  
      • (not (= (list 1 2)  (list 1 2)))            , retorna T
      • (not (equal  (list 1 2)  (list 1 2)))            , retorna nil
      • (not (> 2 0))            , retorna nil;  
      • (not (> 1 1))             , retorna T
      • (not T)              , retorna nil
      • (not nil)              , retorna T



No próximo post, eu irei falar sobre as funções condicionais. Até lá, pessoal!




REFERÊNCIAS

- Cadeias de caracteres (strings): http://www.ime.usp.br/~pf/algoritmos/aulas/strings.html
- Operadores lógicos: http://pt.wikipedia.org/wiki/Operadores_l%C3%B3gicos
AutoLISP III- Funções de repetição e condicionais, Obter e converter informação, João Tavares e Joaquim Fonseca - DEMec, FEUP
- Fórum com discurssão sobre "=, eq, equal":  http://forums.augi.com/showthread.php?6240-eq-equal




EXTRAS

- Exemplo que mostra um caso, onde as funções "=" e "eq" retornam valores diferentes:
  1) desenhe uma entidade simples qualquer, como por exemplo uma linha.
  2) Salvando o nome da entidade desenhada na variável entA (selecione a linha após o comando): (setq entA (car (entsel)))
  3) Salvando o nome da mesma entidade desenhada na variável entB (selecione a linha após o comando): (setq entB (car (entsel)))
  4) Comparação usando "=": (= entA entB)           , retorna nil ;
  5) Comparação usando "eq": (eq entA entB)           , retorna T

segunda-feira, 23 de abril de 2012

3 - Listas em AutoLisp (list) - PARTE 2 - Funções: length, cons, append, subst

Olá Pessoal, neste post irei continuar falando sobre funções que manipulam listas. No post passado, falei como criar listas e como obter um elemento de uma posição da lista. Neste post, irei falar como adicionar elementos numa lista existente, como trocar elementos e como saber a quantidade de elementos numa lista qualquer.


Quantidade de elementos em uma lista

Através da função length seguido pelo nome da lista, podemos descobrir quantos elementos existem nesta lista. OBS: cada sub lista é considerada um elemento da lista.
Exemplos:
- (length (list))
   retorna 0
- (length (list 1 2 3))
   retorna 3
- criando uma lista na variável a1: (setq a1 (list "teste" (list (list 1 2 3) 10)))
   criada a lista: ("teste" ((1 2 3) 10))
   verificando o tamanho da lista contida em a1: (length a1)
   retorna 2



Adicionando elementos em uma lista existente

1 - Função CONS

A função cons permite adicionar um átomo ou uma sub lista como um novo elemento de uma lista. A sua sintaxe é a seguinte: (cons NovoItem ListaA), onde NovoItem é um átomo ou uma lista, e ListaA é a lista no qual receberá o novo elemento. OBS: só é possível adicionar um novo elemento de cada vez na lista, e este elemento será posicionado na primeira posição da lista existente.
Exemplos:
- adicionando o átomo 15 na lista (5 10): (cons 15 (list 5 10))
   retorna a nova lista: (15 5 10)
- adicionando a sub lista (1 2) na lista (3 4): (cons (list 1 2) (list 3 4))
   retorna a lista: ((1 2) 3 4)
- adicionando o átomo "teste" na lista vazia (): (cons "teste" (list))
  retorna a lista: ("teste")

OBS2: a função cons também é utilizada para construirmos um tipo de lista especial (list association) que contém 2 pares (o primeiro elemento funciona como um cabeçalho e o segundo elemento é associado a este cabeçalho). Este tipo de estrutura é muito utilizado em entidades do AutoCAD, quando se manipula em AutoLISP. Num post futuro irei falar sobre este tipo de estrutura.


2 - Função APPEND

A função append, é um pouco parecida com a função cons, porém a forma que ela funciona é um pouco diferente. Nesta função, o objetivo é anexar alguma lista numa outra lista. A sintaxe da função é a seguinte: (append (lista1) (lista2) (lista3) ... ) , assim pode-se  juntar N-listas em uma única lista.
Exemplos:
- juntando a lista (10 20) com a lista (30 40): (append (list 10 20) (list 30 40))
  retorna a lista: (10 20 30 40)
- criando uma lista na variável teste: (setq teste (list 1 2 3))
  anexando no ínicio da lista teste, os elementos -1 e 0: (append (list -1 0) teste)
  retorna a lista: (-1 0 1 2 3)
- anexando no final da lista ("abc" "def") a sub lista ("123" "456"): (append (list "abc" "def") (list (list "123" "456")))
  retorna a lista: ("abc" "def" ("123" "456"))



Substituindo elementos em uma lista

Utilizando a função subst, podemos trocar um elemento de uma lista por outro. A sintaxe da função é a seguinte: (subst NovoElemento VelhoElemento Lista) , onde NovoElemento pode ser um átomo ou uma lista e VelhoElemento deve ser um item existente na Lista. OBS: caso o velho elemento definido não exista dentro da Lista, então nada será substituído, e será retornado a lista original. E se existir mais de uma vez o velho elemento, então todos estes elementos repetidos serão trocados pelo novo elemento na lista
Exemplos:
- substituindo o átomo "dois" pelo átomo 2 na lista (1 "dois" 3): (subst 2 "dois" (list 1 "dois" 3))
 retorna: (1 2 3)
- substituindo o átomo 1 pelo átomo "troca" na lista (1 1 2 1 3 1 4): (subst "troca" 1 (list 1 1 2 1 3 1 4))
  retorna: ("troca" "troca" 2 "troca" 3 "troca" 4)
- troca cada átomo 1 por 10 na lista (10 20 30): (subst 10 1 (list 10 20 30))
  retorna a mesma lista, pois não houve troca: (10 20 30)
- substituindo a sub lista (1 2) pelo átomo 12 na lista ((1 2) 3 4): (subst 12 (list 1 2) (list (list 1 2) 3 4))
  retorna a lista: (12 3 4)
- utilizando a função subst em conjunto com a função nth; Dado a variável teste, que contém a lista  (1 2 3 4), substituir o segundo elemento da lista por "num2":
  criando a lista: (setq teste (list 1 2 3 4))
  substituindo o segundo elemento da lista: (subst "num2" (nth 1 teste) teste)
  retorna a lista: (1 "num2" 3 4)



Bom, assim termino esta pequena introdução sobre listas. Vocês devem ter notado, que não falei, de nenhuma função que deleta itens de forma direta da lista. Isto devido ao simples fato de que não existe (ou eu não conheço?), mas o leitor não precisa ficar assustado, pois existe funções em ActiveX, que permitem fazer esta operação comum. Como considero o assunto sobre ActiveX, um pouco mais avançado, não irei falar sobre estas funções neste momento.

No próximo post, eu irei falar sobre operadores de comparação e operadores lógicos, para introduzir o assunto do post seguinte, que é funções de repetição. Até lá, pessoal!

2 - Listas em AutoLisp (list) - PARTE 1 - Funções: list, car, cdr e nth

Olá Pessoal, neste post eu irei falar sobre a manipulação de listas no AutoLisp, que pode-se dizer que é a estrutura mais importante que existe em lisp, isto fica mais evidente com o fato de LISP significar LISt Processing (processamento de listas).

Neste post, eu irei focar na manipulação de listas através dos comandos básicos presentes na linguagem. Num post futuro, irei falar dos comandos para manipulação de listas, utilizando o ActiveX, que é uma expansão do Visual Lisp, que amplia em muito o AutoLisp.



CRIANDO LISTAS


Para criar uma lista, usamos a palavra chave list, seguido dos itens no qual se deseja adicionar a lista. Estes itens podem ser de qualquer tipo, números, strings, outras listas (sub listas), ou uma mistura de várias coisas.
Exemplos:
- criando uma lista com os números 1, 2 e 3: (list 1 2 3) 
   retorna: (1 2 3)
- criando uma lista com as strings "Autolisp" e "Brasil": (list "Autolisp" "Brasil")
   retorna: ("Autolisp" "Brasil")
- criando uma lista que contém as duas listas dos exemplos anteriores: (list (list 1 2 3) (list "Autolisp" "Brasil"))
  retorna: ((1 2 3) ("Autolisp" "Brasil"))

O caractere ' nos permite substituir a palavra chave list em alguns casos, na verdade este caractere é equivalente ao comando quota do AutoLisp, que não entrarei em detalhes.
Exemplo do uso do caractere ' , onde queremos criar uma lista com os seguintes itens: o número 1, uma sub lista com os números 2 e 3, e o número 4:
(list 1 '(2 3) 4)
retorna: (1 (2 3) 4)

Exemplo que não funciona com o caractere ' :
('( 1 2 3)) (NÃO FUNCIONA)

Para fazer o exemplo anterior funcionar, podemos associar a lista em uma variável qualquer, assim podemos utilizar do caractere ' , como mostrado no exemplo abaixo:
(setq variavel '( 1 2 3))
que retorna a lista: (1 2 3)



RECUPERANDO ELEMENTOS DA LISTA

1 - FUNÇÕES CAR E CDR
Uma maneira de recuperar os elementos de uma lista, é utilizando as funções car e cdr. A função car, recupera sempre o primeiro elemento de uma lista, que pode ser um átomo ou uma sub lista, ou seja, qualquer coisa que esteja como primeiro item da lista.
Exemplos, utilizando a função car:
- Exemplo 1: Temos a seguinte lista: (10 20 30 40)
                      Utilizando da função car: (car (list 10 20 30 40))
                      Obtemos o átomo: 10
- Exemplo 2: Temos a váriavel listaObjetos com os itens "autolisp", 30, 3.14
                      Criando a lista: (setq listaObjetos (list "autolisp" 30 3.14))
                      Lista gerada: ("autolisp" 30 3.14)
                      Utilizando da função car: (car listaObjetos)
                      Obtemos o átomo: "autolisp"
- Exemplo 3: Temos uma lista com uma sub lista contendo os números 1, 2 e 3, e uma outra sub lista contendo os números 4, 5 e 6.
                       Utilizando da função car: (car (list (list 1 2 3) (list 4 5 6)))
                       Obtemos a lista: (1 2 3)


A função cdr, recupera todos os itens da lista, exceto o primeiro. Utilizando os mesmo exemplos anteriores, temos:

Exemplos, utilizando a função cdr:
- Exemplo 1: Temos a seguinte lista: (10 20 30 40)
                      Utilizando da função cdr: (cdr (list 10 20 30 40))
                      Obtemos a lista: (20 30 40)
- Exemplo 2: Temos a váriavel listaObjetos com os itens "autolisp", 30, 3.14
                      Criando a lista: (setq listaObjetos (list "autolisp" 30 3.14))
                      Lista gerada: ("autolisp" 30 3.14)
                      Utilizando da função cdr: (cdr listaObjetos)
                      Obtemos a lista: (30 3.14)
- Exemplo 3: Temos uma lista com uma sub lista contendo os números 1, 2 e 3, e uma outra sub lista contendo os números 4, 5 e 6.
                       Utilizando da função cdr: (cdr (list (list 1 2 3) (list 4 5 6)))
                       Obtemos uma lista com um único item, que é uma sub lista: ((4 5 6))


Para obtermos por exemplo o segundo item da lista, precisamos utilizarmos a função cdr, que retorna a lista sem o primeiro item seguido da função car, como mostrado abaixo para a seguinte lista (10 20 30 40 50):
(setq lista (list 10 20 30 40 50))
(setq novaLista (cdr lista))
(setq novaNovaLista (car novaLista))

Recuperar os itens desta forma é bem ineficiente, pois se tivermos que recuperar o quarto item, temos que invocar três vezes a função cdr e por fim a função car. Felizmente, lisp permite concatenar as funções cdr e car, assim para o caso anterior, podemos usar a função cadddr, que pode ser lida de trás para frente, onde cada "d" significa uma execução da função cdr, e cada "a" significa a execução da função car.

Abaixo temos uma listagem de funções permitidas com a junção das funções car com cdr, lembrando que a chamada das funções car e cdr é feita de trás para frente nestas funções:

caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr


Infelizmente, nem sempre temos uma função que desejamos, quando vamos obter um item, por exemplo para pegar o quinto item da lista (10 20 30 40 50), temos que executar quatro vezes a função cdr, seguido de uma execução da função car. Não existe a função caddddr em lisp, então temos que mesclar as funções disponíveis para se conseguir o efeito desejado.


2 - FUNÇÃO NTH

Através da função nth, podemos acessar de forma mais direta elementos da lista. Sabendo-se qual a posição do elemento na lista, a função nth é usada da seguinte forma: (nth x listaA) , onde x é a posição do elemento na lista e listaA é a lista no qual está efetuando a operação. OBS: a primeira posição da lista é sempre 0, e a última posição da lista é o número de elementos menos um.

Exemplos, utilizando a função nth:
- Exemplo 1: Temos a seguinte lista: (10 20 30 40)
                     Utilizando da função nth, queremos obter o terceiro elemento da lista: (nth 2 (list 10 20 30 40))
                     Obtemos o átomo: 30
- Exemplo 2: Temos a váriavel listaObjetos com os itens "autolisp", 30, 3.14
                      Criando a lista: (setq listaObjetos (list "autolisp" 30 3.14))
                      Lista gerada: ("autolisp" 30 3.14)
                    Utilizando da função nth, queremos obter o primeiro elemento da lista: (nth 0 listaObjetos)
                      Obtemos o átomo: "autolisp"
- Exemplo 3: Temos uma lista com uma sub lista contendo os números 1, 2 e 3, e uma outra sub lista contendo os números 4, 5 e 6.
                    Utilizando da função nth, queremos obter o segundo elemento da lista: (nth 1 (list (list 1 2 3) (list 4 5 6)))
                    Obtemos a sub lista: (4 5 6)




OBSERVAÇÕES:

- Quando tenta-se obter um elemento inexistente de uma lista, como por exemplo uma lista com 3 elementos, tenta-se acessar o quinto elemento, é obtido o valor nil;
- Um erro é obtido em situações no qual é aplicados as funções car, cdr ou nth, em elementos que não são listas;



No próximo post, irei continuar falando de outras funções que manipulam listas.

segunda-feira, 16 de abril de 2012

1 - Introdução ao AutoLISP

Um pouco de história

O AutoLISP é um dialeto da antiga linguagem LISP. A linguagem LISP foi concebida por John McCarthy em 1958, e o seu nome vem de LISt Processing, pois a lista é a estrutura de dados fundamental da linguagem. 
LISP é a segunda mais antiga linguagem de programação de alto nível criada, perdendo apenar para a linguagem FORTRAN.
O principal paradigma de programação de LISP é a programação funcional, e além disso a linguagem não é compilada, e sim interpretada, ou seja, existe um programa instalado chamado interpretador, que executa o código fonte, para em seguida ser executado pelo sistema operacional ou processador.

O AutoLISP foi criado especificamente para ser utilizado com o programa AutoCAD da Autodesk. E ele foi introduzido no AutoCAD em 1986 na versão 2.18. Atualmente o interpretador e o ambiente de programação, vem junto com o AutoCAD, exceto nas versões do AutoCAD LT.



Tipos de dados básicos

Na linguagem AutoLisp, existe praticamente dois tipos de dados fundamentais: o átomo e a lista. 
O átomo pode ser numérico ou alfanumérico. Além disso, existem dois tipos de átomos especiais muito usados, o nil e o T. O nil representa o valor nulo e ao mesmo tempo uma lista vazia, o T representa o símbolo verdadeiro (true).
A lista é a associação de átomos ou outras listas representandos entre parêntesis.


Expressões

- Cada instrução deve iniciar sempre com um abre parêntesis "(" e terminar com um fecha parêntesis ")";

- O AutoLisp utiliza a notação infixa quando efetuamos uma expressão matemática, isto é, primeiramente vem o operador seguidos dos operandos.
Exemplo: 10 + 20 + 30 + 40
Em AutoLisp, você escreveria assim: 
(+ 10 20 30 40)

- Qualquer coisa avaliada em AutoLisp retorna um valor como resultado;



Declarando variáveis

Para declarar uma variável, utilizamos a palavra chave setq seguida de um nome válido para a variável e seguida de um átomo ou uma expressão.
Exemplos:
- declarando uma variável chamada teste com o valor 10: (setq teste 10) 
- declarando uma variável chamada conta com o resultado da expressão 10 * 2: (setq conta (* 10 2))
- declarando uma variável chamada valor com o valor nil (nulo): (setq valor nil)
- declarando uma variável chamada lista com uma lista com os inteiros 1, 2 e 3: (setq lista (list 1 2 3))



Executando código AutoLisp pela linha de comando do AutoCAD


A execução de comandos AutoLisp pela linha de comando do AutoCAD é muito útil para realizar pequenos testes. Para isso, digite na linha de comando a expressão ou função desejada e aperte ENTER. O resultado da avaliação do interpretador é retornado na linha de comando para o usuário. OBS: não esqueça de sempre utilizar dos parêntesis ao iniciar uma expressão.


Carregando programas AutoLisp no AutoCAD

Entre na opção Load Application, presente no menu Tools no modo do AutoCAD Classic. Se você estiver utilizado as ribbons ao invés do menu clássico, vá na aba Manage, e em Applications, clique em Load Application. Outra maneira de chegar até está tela, é digitando na linha de comando o comando appload (ou simplesmente "ap"), seguido de um ENTER.
Na tela que se segue, navegue até o diretório e clique no arquivo desejado a ser carregado, e em seguida clique no botão Load. OBS: arquivos lisp tem a extensão .lsp .


Próximo POST

No próximo post, eu irei falar sobre listas: como criar, recuperar elementos, substituir, deletar, etc.


REFERÊNCIAS:

- Wikipédia;
- AutoLISP - I Introdução, João Tavares e Joaquim Fonseca - DEMec, FEUP