collapse

* Posts Recentes

Amplificador - Rockboard HA 1 In-Ear por almamater
[Ontem às 19:13]


O que é isto ? por KammutierSpule
[26 de Março de 2024, 19:35]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Emulador NES em ESP32 por dropes
[13 de Março de 2024, 21:19]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Meu novo robô por josecarlos
[06 de Janeiro de 2024, 16:46]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]

Autor Tópico: TCL ("ticle")  (Lida 12330 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
TCL ("ticle")
« em: 24 de Março de 2015, 20:45 »
Embora pouco conhecida, TCL é uma das minhas linguagens favoritas; é o meu canivete suíço do software.
Como tal venho mostrar-vos algumas linhas de código nesta linguagem. Quem usar linux já tem o interpretador de TCL instalado e é só usar o comando tclsh para entrar numa linha de comando do interpretador (exit é o comando para sair, ou CTRL+C).

Eu gosto de TCL (e Tk, a biblioteca gráfica que nasceu com o TCL, também) por várias razões, entre as quais a simplicidade da linguagem. Em TCL cada linha do script (programa) corresponde a um comando e respectivos argumentos. O interpretador de TCL parte cada linha em palavras, pelos espaços, e interpreta a 1ª palavra da linha como o nome do comando e as restantes como argumentos desse comando. Quando é preciso que uma palavra tenha espaços (mesmo que sejam fins de linha!), envolve-se essa palavra em aspas "".
Por exemplo o comando puts serve para escrever em canais e adiciona automaticamente um fim de linha; por omissão o puts escreve para o canal stdout (tipicamente é o "ecrã"):

puts olá

Se quisermos escrever uma string com espaços, então temos que o envolver em aspas:

puts "olá mundo"

E isto também funciona:

puts "Olá mundo.
Agora uma nova linha.
E outra."


Um comentário é uma linha começada por #. Em TCL só existem 3 tipos de dados: string, lista e array. As listas só podem conter strings e outras listas, e os arrays em TCL são associativos (tabelas de hash). Uma variável pode conter um valor de qualquer um destes tipos, e o comando set é forma mais habitual de criar ou alterar variáveis:

# set <nome-da-variável> <valor>
set nick Njay

Se a variável não existia previamente, o set cria-a. Podemos apagar uma variável com

# unset <nome-da-variável>
unset nick

Usar o valor da variável faz-se prefixando-a com um dólar, $ . Para mostrar no ecrã o valor da variável nick,

puts $nick

e para copiá-la para outra

set nick2 $nick

Se quisermos misturar variáveis com texto basta enfiar as variáveis no meio de uma string:

puts "O meu nick é $nick"

Depois de separar a linha em palavras, o interpretador de TCL pega em cada palavra e faz as chamadas substituições, sendo que uma delas é procurar instâncias de variáveis e substituí-las pelo valor da variável. Assim, o comando puts acima não recebe como argumento "O meu nick é $nick" mas sim "O meu nick é Njay" . Parte da simplicidade do TCL é que ele limita-se a passar "strings" aos comandos, e os comandos depois é que decidem o que fazer com essas string. Isto é muito poderoso.

Para passar um argumento a um comando sem que sejam feitas substituições, envolve-se o argumento em chavetas {}. Se no exemplo acima quiséssemos mesmo imprimir no ecrã a string "O meu nick é $nick", sem que a variável fosse substituída pelo seu valor, poderiamos fazer assim:

puts {O meu nick é $nick}

Outra coisa muito poderosa em TCL é que é muito fácil lidar com ficheiros e com sockets. Abrir e carregar o conteúdo de um ficheiro de texto para uma variável é tão simples como

set fd [open data.txt r]
set data [read $fd]
close $fd


Aqui usei 4 comandos: open, set, read e close. Além das variáveis, outra das substituições que o interpretador de TCL faz quando está a parsar uma linha, é a "substituição de comandos", quando estes aparecem em parentesis rectos []. Ao fazer as substituições nos argumentos do comando set na 1ª linha do script acima, o interpretador vê os [] e pega em todo o texto que contém, parsa-o e executa-o como se fosse uma linha isolada no script. Portanto invoca o comando open com os argumentos data.txt (nome do ficheiro) e r (abrir o ficheiro para leitura), e substitui os [] pelo resultado do comando, que é um identificador de ficheiro aberto. Este identificador é então passado ao comando set como 2º argumento, que cria a variável fd para o guardar.
Na 2ª linha o comando read lê todo o conteúdo do ficheiro e coloca-o na variável data. Na 3ª linha o ficheiro é fechado com close.

É igualmente fácil abrir um socket e enviar e receber dados. Em TCL o I/O ocorre em canais e usam-se as mesmas funções para ler, escrever, configurar e fechar. Muda o comando que abre um canal, dependendo do tipo de canal; open para ficheiros e portas série, socket para sockets. Abrir uma ligação TCP para um servidor web e obter uma página é simples:

set sock [socket lusorobotica.com 80]
puts $sock "GET / HTTP/1.0\nHost: lusorobotica.com\nConnection: close\n"
flush $sock
set response [read $sock]
close $sock
puts $response


A 1ª linha abre uma ligação TCP para o servidor lusorobotica.com no porto 80 (o porto por omissão para servidores HTTP) com o comando socket, e guarda o identificador do socket na variável sock. Depois o puts envia ao servidor o pedido HTTP, e o flush "despeja" os buffers do canal, garantindo que o que foi escrito pelo puts foi *mesmo* enviado para a rede. Depois é lida toda a resposta do servidor web para a variável response, o socket é fechado e a resposta é impressa no ecrã. Reparem que o pedido HTTP enviado pelo puts é uma string constante, mas eu usei aspas em vez de chavetas; se eu usasse chavetas, não ocorreria a substituição dos caracteres \n por um real caractere de fim de linha.
A resposta tem no inicio algumas linhas que correspondem os cabeçalhos HTTP de resposta, e depois a página. Mais tarde posso explicar como separar ambos, mas para já não quero complicar mais.

É igualmente simples abrir uma ligação a uma porta série, por exemplo para falar com um Arduino, ou executar outras aplicações. Em TCL "tudo são strings" e isso simplifica muito as interfaces dos comandos e facilita imenso a inter-operabilidade.

Podem executar os comandos 1 a 1 na tcl shell (tclsh) ou metê-los num ficheiro e passar o nome do ficheiro como argumento à tclsh para executar o script todo. Em linux é possível executar o script directamente activando a flag de executável do ficheiro e adicionando isto logo ao inicio do script (espero que esteja certo, não costumo usar Linux):

#! /usr/bin/env tclsh

End of Part I
« Última modificação: 25 de Março de 2015, 13:04 por Njay »

Offline Nunito

  • Mini Robot
  • *
  • Mensagens: 923
Re: TCL ("ticle")
« Responder #1 em: 25 de Março de 2015, 08:37 »
Muito bom.
Fácil de interpretar.
Isso dá para windows?

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: TCL ("ticle")
« Responder #2 em: 25 de Março de 2015, 12:52 »
Sim, há para Windows e outras plataformas. Podes sacar o instalador da última ou penúltima versão aqui: http://www.activestate.com/activetcl/downloads

Em alternativa, deixo aqui em anexo a minha versão do package para windows, que é o TCL/TK8.3 mas reduzido ao essencial com umas extensões extra para Windows e que não é preciso instalar, basta descomprimir e o interpretador (tclsh) está da directoria bin/ (mais fácil se adicionares essa directoria ao path). A tclsh é uma consola muito básica, eu normalmente uso outra consola mais inteligente que é a TkCon (que está feita em TCL/TK, é um script TCL!); para correr a TkCon há um bat na raíz da directoria. Na directoria doc está o help, que contém *toda* a documentação do TCL/TK (excepto a das extensões que eu juntei, que têm uns html com doc lá dentro); acabei por perder a doc do TCL8.3 e por isso o ficheiro que lá está é a do 8.4, mas as diferenças são muito poucas.
Este zip de ~3MB (~10MB descomprimido) faz maravilhas ;)
« Última modificação: 16 de Maio de 2015, 21:44 por Njay »

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.733
  • Helpdesk do sitio
Re: TCL ("ticle")
« Responder #3 em: 20 de Abril de 2015, 23:57 »
Parabéns, para quando mais um petisco em TCL?

Já agora, e a titulo de curiosidade, quem tem o IDE do Arduino já lá tem o TCL enfiado numa pasta.
Avr fanboy

Offline TigPT

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 5.372
    • Tiago Rodrigues
Re: TCL ("ticle")
« Responder #4 em: 21 de Abril de 2015, 12:24 »
Não conhecia, e é sempre útil ter opções de scripting fáceis de utilizar para simplificar tarefas do dia-a-dia.

Obrigado Nuno por este cheirinho do TCL.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: TCL ("ticle")
« Responder #5 em: 16 de Maio de 2015, 21:48 »
"Petisco de TCL", lol... É verdade tens razão senso, o TCL vem "embebido" no pacote do arduino. TCL/Tk é um bocado "low-profile" mas quando vamos cavar encontra-se por aí em vários sítios.

Vou fazer um twist a este "tutorial". Perguntem como se faz qualquer-coisa em TCL/Tk. Coisas relativamente simples claro, tipo como se ordena uma lista, como se processa um ficheiro de texto linha-a-linha, etc; não aceito perguntas do género "como se faz um editor com sintaxe highlight" (embora na verdade não seja mto dificil :o ).
« Última modificação: 16 de Maio de 2015, 21:49 por Njay »

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.947
  • NERD!
Re: TCL ("ticle")
« Responder #6 em: 16 de Maio de 2015, 22:29 »
Se me permites uma proposta: abrir um ficheiro de texto, correr uma regex, e retornar (para um ficheiro ou consola) todos os matches.

É uma das tarefas que já me poupou muitas horas de trabalho, e que atualmente executo em python por ser rápido e fácil. Em python:
Código: [Seleccione]
import re

f = open ("exemplo.txt")
texto = f.read()
f.close()

for result in re.findall("\d{3}",texto): #encontra numeros de 3 digitos
   print result

Offline Hugu

  • Mini Robot
  • *
  • Mensagens: 5.602
  • Keyboard not found. Press any key to continue.
    • [url=www.g7electronica.net]G7 Electrónica.net[/url]
Re: TCL ("ticle")
« Responder #7 em: 16 de Maio de 2015, 22:49 »
@off-topic: precisava dum script podia ser em python que me pegasse em um txt, com mails pra lá atirados e que me faça ordenação em grupos de x mails por ficheiro txt separado, com respectiva exclusao de mails repetidos... tinha um script que fazia quase isto, mas deixou de dar porque aquilo tinha um deadtimmer e nao houve mais upgrades ou novas versoes do autor :(

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: TCL ("ticle")
« Responder #8 em: 16 de Maio de 2015, 23:29 »
Se me permites uma proposta: abrir um ficheiro de texto, correr uma regex, e retornar (para um ficheiro ou consola) todos os matches.

É uma das tarefas que já me poupou muitas horas de trabalho, e que atualmente executo em python por ser rápido e fácil. Em python:
Código: [Seleccione]
import re

f = open ("exemplo.txt")
texto = f.read()
f.close()

for result in re.findall("\d{3}",texto): #encontra numeros de 3 digitos
   print result

Em TCL seria muito parecido:

Código: [Seleccione]
set fd  [open "exemplo.txt" r]
set data  [read $fd]
close $fd

foreach line [split $data \n]  {
    if [regexp -- "\\d{3}" $line match]  {
        puts $line
    }
}

A sintaxe das expressões regulares é basicamente a mesma que em python (é usada a mesma lib de re em C lá por baixo de certeza), as diferenças são apenas por causa da forma como representas certos caracteres.

split é um comando que retorna uma lista de strings, gerada partindo em bocados a string indicada como 1º argumento, sempre que encontra um dos caracteres indicados no 2º argumento. Assim, o comando split $data \n retorna uma lista em que cada elemento é uma linha do ficheiro.

Depois o comando foreach serve para percorrer listas elemento a elemento e fazer alguma coisa com eles; o nome diz tudo, "for each" -> "para cada" (para cada elemento da lista, faz ...). O 1º argumento é o nome de uma variável onde a cada iteração do foreach é colocado o elemento. O 2º argumento do foreach é a lista a percorrer e o 3º é o script a executar para cada elemento.

Finalmente há um if que verifica se houve um match da linha com a expressão regular e em caso afirmativo envia a linha para o stdout (vulgo, "imprime a linha" :) ).

O comando regexp tem um parâmetro não usado neste exemplo, que é o "match". Este é o nome de uma variável que o regexp cria com o texto que fez o 1º match da string. O argumento está no exemplo porque é obrigatório no comando, mas estou a ignorá-lo (não faço nada com ele). Mas podia usar-se para ter mais informação no output, se relevante para a aplicação.
« Última modificação: 16 de Maio de 2015, 23:43 por Njay »

Offline dropes

  • Mini Robot
  • *
  • Mensagens: 2.189
Re: TCL ("ticle")
« Responder #9 em: 16 de Maio de 2015, 23:45 »
Na era do DOS tudo o que eram scripts eram à base de batchs, até foi assim que comecei a interessar-me por programação e ainda fiz uns jogos, à base de linhas de comandos como é óbvio.

O DOS também tinha incluído uma versão BASIC que achei uma maravilha, muito simples passando mais tarde para o Pascal em paralelo com o C.

Em Pascal fazia de tudo, desde de crackar jogos, scripts para tudo e mais alguma coisa, criar jogos, efeitos gráficos mesmo tridimensionais, acesso directo à memória gráfica, não haviam limites...
Infelizmente perdeu continuidade quando se entrou em modo windows e passou a ser uma linguagem ultrapassada, entretanto o C permaneceu até hoje.

No presente não entendo mesmo nada de C, entretanto ainda dou uns toques em VB no que toca a linguagem informática, o mesmo se passa com os microcontroladores, 0 em C, programando sempre em Basic (BascomAVR), tirando os casos em que tenho de recorrer ao assemby 8051 ou AVR.

Sei que devia aprender C, até os arduinos o têm mas há algo que me desagrada desde a época do DOS, por isso fujo um pouco a esta linguagem, o que hoje em dia é essencial entende-la...

No que toca a opiniões, prefiro saber trabalhar bem com uma linguagem do que saber várias assim por alto, com os micros passa-se o mesmo, não vario muito do Atmega 8b e nunca me deixou ficar mal para o que tenho feito  :)

TCL nunca tinha ouvido falar, é como quando me iniciei em ladder para PLCs, que porcaria, é que nem linguagem pode ser considerada, foi sem dúvida a pior experiência que já tive em "programação", tudo muito visual com uma apresentação confusa de ser interpretada, bonequinhos por tudo o que é sitio, podendo ser visto o código gerado em assembly, é que até em texto corrido seria muito mais rápido de se programar do que neste tipo de interface, enfim... são gostos.

Boa iniciativa aqui do Njay apresentado uma solução simples para pequenos scipts que nos vão ajudando nas rotinas especificas do dia a dia   ::)

Offline artur36

  • Mini Robot
  • *
  • Mensagens: 795
Re: TCL (&quot;ticle&quot;)
« Responder #10 em: 17 de Maio de 2015, 10:05 »


Citação de: dropes

TCL nunca tinha ouvido falar, é como quando me iniciei em ladder para PLCs, que porcaria, é que nem linguagem pode ser considerada, foi sem dúvida a pior experiência que já tive em "programação", tudo muito visual com uma apresentação confusa de ser interpretada, bonequinhos por tudo o que é sitio, podendo ser visto o código gerado em assembly, é que até em texto corrido seria muito mais rápido de se programar do que neste tipo de interface, enfim... são gostos.

O ladder tem de ser entendido no contexto em que foi criado, quando appareceram os primeiros autómatos os técnicos de automação que existiam não eram programadores mas sim electricistas/projectistas que a única linguagem que conheciam era lógica com relés e daí surgiu o ladder como linguagem perfeita para autómatos, mesmo hoje em dia um bom electricista é capaz de interpretar um programa de ladder sem nunca ter estudado programação.
Para mim a dificuldade inicial do ladder prende-se com a estruturação inicial do programa, quando se compreende o conceito de máquina de estados e se parte de um Grafcet a programação é relativamente simples. Mas para quem quiser uma linguagem de programação em texto e conhecida pelo menos a siemens já disponibiliza uma linguagem de programação de alto nível derivada do C.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: TCL ("ticle")
« Responder #11 em: 17 de Maio de 2015, 14:40 »
Pensava que programavas os AVR em C, dropes. Tens que aprender C, até é uma vergonha um gajo do baixo nível não saber C  :o :P, hehehe

Bom, voltando ao tópico, podemos agarrar no código que procura expressões regulares em linhas dum ficheiro e fazer dele um comando para ser mais útil. Em TCL criam-se comandos com o comando proc (e chamamos-lhes "proc" para não estar sempre a dizer "comando"), que aceita 3 argumentos: o nome do novo comando, a lista de argumentos do comando e o código. Portanto ficaria assim:

proc ScanFileLines {file_name regular_expression}  {
    set fd  [open $file_name r]
    set data  [read $fd]
    close $fd

    foreach line [split $data \n]  {
        if [regexp -- $regular_expression $line match]  {
            puts $line
        }
    }
}


Todos os comandos em TCL retornam alguma coisa, nem que seja uma string vazia. Se um proc não retornar com o comando return (por exemplo return "sucesso"), ele retorna o resultado do último comando executado no proc. Neste caso não retornamos nada explicitamente no proc ScanFileLines, que é como quem diz que não queremos retornar nada de especial. O proc criado leva 2 argumentos, o nome do ficheiro a inspeccionar e a expressão regular. Invocar este proc para fazer o trabalho do exemplo original é assim:

ScanFileLines "exemplo.txt" "\\d{3}"

Agora tendo este proc fica mais fácil fazer uma ferramenta de linha de comando para esta tarefa. O TCL cria automaticamente uma lista com os argumentos passados ao script na linha de comando, colocando essa lista na variável argv . Se enfiarmos o nosso script num ficheiro chamado scanfilelines.tcl, e o invocarmos assim

tclsh scanfilelines.tcl arg1 arg2 arg3

a variável argv terá uma lista com 3 elementos, os 3 argumentos da linha de comando: {arg1 arg2 arg3} . Vamos agora convencionar que passamos ao nosso script no 1º argumento o nome do ficheiro e no 2º a expressão regular, para usar assim

tclsh scanfilelines.tcl exemplo.txt \d{3}   (*)

Dentro do script temos que extrair esses argumentos para variáveis separadas para passarmos ao proc ScanFileLines. Há 2 ou 3 maneiras de fazer isto, mas vamos começar pela mais explicita (mas não a mais compacta), que é usar o comando lindex (list index), que retorna o elemento de índice X de uma lista, sendo que X começa em 0, ou seja, o 1º elemento de uma lista é o que está no índice 0. Ficaria então assim:

set file_name  [lindex $argv 0]
set regular_expression  [lindex $argv 1]


O comando lindex aceita 2 argumentos, a lista e o índice a extrair. Agora já podemos invocar o nosso proc:

ScanFileLines $file_name $regular_expression

E fica em anexo o script completo (em .zip que o fórum não aceita .tcl).

Venham de lá mais pedidos de "como é que se faz X" em TCL...


(*) isto é em windows, \d{3} pode ter que ser passado de forma ligeiramente diferente noutras shells
« Última modificação: 17 de Maio de 2015, 21:15 por Njay »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: TCL ("ticle")
« Responder #12 em: 17 de Maio de 2015, 14:49 »
@off-topic: precisava dum script podia ser em python que me pegasse em um txt, com mails pra lá atirados e que me faça ordenação em grupos de x mails por ficheiro txt separado, com respectiva exclusao de mails repetidos... (...)

Com esses requisitos tão esparsos eu nem arrisco uma estimativa de preço ;)

Offline dropes

  • Mini Robot
  • *
  • Mensagens: 2.189
Re: TCL ("ticle")
« Responder #13 em: 18 de Maio de 2015, 11:30 »
Pensava que programavas os AVR em C, dropes. Tens que aprender C, até é uma vergonha um gajo do baixo nível não saber C  :o :P, hehehe

Shame on me, é que nem um arduino sei programar  :-[ :P

Quanto ao ladder também me foi explicado que um electricista conseguia entender mesmo sem saber programar, já ao contrário... é frustrante (omron, siemens ou schneider, 3 programas lindos que foram desinstalados mal acabei a formação).

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: TCL ("ticle")
« Responder #14 em: 22 de Maio de 2015, 13:57 »
Então, e mais desafios para fazer em TCL?

Olha um contador de palavras num ficheiro:

# Obter o nome do ficheiro da linha de comando (1º argumento)
set file_name  [lindex $argv 0]
# Abrir e ler o ficheiro todo para a variável txt
set fd  [open $file_name r]
set txt  [read $fd]
close $fd
# Substituir múltiplos espaços, tabs e fins de linha por 1 único espaço
regsub -all "\\s\\s+" $txt " " txt
# Partir o texto pelos espaços, guardando o resultado (uma lista, de palavras) na variável words
set words  [split $txt " "]
# E escrever no ecran o número de palavras
puts "[llenght $words] palavras"


Ainda não testei, mas deve funcionar :)

Já fazíamos era uma função para abrir um ficheiro de texto e retornar o conteúdo:

proc LoadTextFile {file_name}  {
    set fd  [open $file_name r]
    set txt  [read $fd]
    close $fd
    return $txt
}


E mais?
« Última modificação: 22 de Maio de 2015, 14:00 por Njay »