O PseudoScript é projetado para ser um ponto de partida para iniciantes. Após dominar os conceitos básicos, os aspirantes podem fazer uma transição mais fácil para a programação real em JavaScript ou Python. Ele fornece uma base sólida em lógica, estruturas de controlo e resolução de problemas sem sobrecarregar os iniciantes com uma sintaxe complexa.
Escopo
Escopo é a região do programa onde uma variável, função ou constante pode ser acedida e utilizada. É como uma "zona de visibilidade" para elementos do código. O escopo determina:
- ✅ Onde uma variável pode ser usada
- ✅ Quando ela existe na memória
- ✅ Quem pode acessá-la
- ❌ Onde ela NÃO pode ser acessada (fora do escopo)
Escopo Global
A variável é acessível em qualquer parte do programa.# Variável global
mensagem = "Olá, mundo!"
funcao funcao1():
imprime(mensagem) # ✅ Tem Acesso
funcao funcao2():
imprime(mensagem) # ✅ Tem Acesso
funcao1() # Olá, mundo!
funcao2() # Olá, mundo!
imprime(mensagem) # ✅ Olá, mundo!Escopo Local
A variável existe apenas dentro de um bloco específico (função, if, loop, etc).
funcao minha_funcao():
variavel_local = "Eu sou local"
imprime(variavel_local) # ✅ Funciona
minha_funcao() # Eu sou local
imprime(variavel_local) # ❌ ERRO: variavel_local não está funcaoinidaEscopo de Bloco
A variável existe apenas dentro de um bloco condicional ou loop.se verdadeiro:
valor = 10 // Escopo de bloco
imprime(valor) // ✅ 10
imprime(valor) // ❌ ERRO: valor não está funcao
---
frase="Olá Mundo!"
cada letra em frase:
imprime(letra) # ✅ Funciona
imprime(letra) // ❌ ERRO: Letra não está neste escopoEscopo de Função
A variável é acessível em toda a função onde foi declarada.funcao exemplo():
pontos = 20
se pontos:
imprime(pontos) # ✅ Acede 'pontos' da função
repeticao = 20
enquanto repeticao >= 0:
imprime(pontos)
repeticao = repeticao + 1 # ✅ Acede 'pontos' da função
exemplo() # Imprime 20 'vinte e uma' vezesEm pseudoscript, a ordem de acesso a variáveis é (de dentro para fora):
- Local - Função atual
- Enclosing - Funções externas
- Global - Módulo inteiro
| ✅ Faça | ❌ Evite |
|---|---|
| Use variáveis locais sempre que possível | Variáveis globais desnecessárias |
| Declare global explicitamente se precisar Misturar escopos | - |
| Use nomes descritivos | Shadowing (nomes iguais em escopos diferentes) |
| Mantenha escopos pequenos e claros | Escopos muito grandes e complexos |
- ✅ Evita conflitos de nomes
- ✅ Organiza o código
- ✅ Facilita manutenção
- ✅ Economiza memória (variáveis locais são destruídas)
- ✅ Evita efeitos colaterais inesperados
Importação de Módulos
A importação de módulos é a forma recomendada de partilhar e reutilizar código em PseudoScript. Um módulo pode exportar funções, variáveis e tipos; ao importar um módulo, trazes essas exportações para o contexto atual, mantendo o código modular e fácil de manter. Tipicamente consegues:
- importar um módulo completo;
- importar só símbolos específicos (funções/constantes);
- renomear (alias) módulos para evitar conflitos.
importar NOME_DO_FICHEIRO # Importa tudo o que está no ficheiro
importar NOME_DO_FICHEIRO como X # Importa e renomeia como XTipos de Dados
São a base para representar informação em PseudoScript.
Cada tipo define o formato dos valores, as operações válidas e frequentemente a forma como os valores são guardados em memória.
A documentação abaixo explica os tipos primitivos e compostos mais comuns e dá exemplos de uso.
- Inteiro (int): números sem parte decimal. Ex.: 0, 42, -7. Exemplo:
a = 10 - Decimal / Real / ponto flutuante (float): números com casas decimais. Ex.: 3.14, -0.5 Exemplo:
pi = 3.14 - Booleano (bool): verdadeiro ou falso — usado para condições. Exemplo: let ativo = true
- Texto / string (string): sequência de caracteres. Exemplo: let nome = "Ana"
- Nulo / indefinido (null / nil / undefined): representa ausência de valor. Exemplo: let resultado = null
idade = 25 # Inteiro
altura = 1.75 # Float (Valores Dacimais)
primeiraLetra = "a" # Char (caractere)
nome = "João" # Texto (O Texto é considerado uma lista de caracteres [char])
isEstudante = verdadeiro # Booleano
resultado = null # Nulo (ausência de valor)- Lista / array: coleção ordenada de valores. Exemplo:
nums = [1, verdadeiro, 'olá'] - Dicionário / mapa: coleção de pares chave–valor. Exemplo:
pessoa = ('nome' -> "João", 'idade' -> 30)
# Lista
notas = [15,16,16,17,17]
# Dicionário / Mapa
dicionario =(
'nome' -> 'John',
'apelido' -> 'Doe',
'idade' -> 27
)Operadores Lógicos
O PseudoScript permite o uso de operadores lógicos simples para criar expressões condicionais e controlar o fluxo do programa.
NOTA: Uma comparação tem SEMPRE como seu resultado um valor booleano
a == b # Igual a
a != b # Diferente de
a > b # Maior que
a < b # Menor que
a >= b # Maior ou igual a
a <= b # Menor ou igual a
# Exemplos:
numero1 = 3
numero2 = 5
imprime(numero1==numero2) # Falso
imprime(numero1>numero2) # Falso
imprime(numero1<numero2) # VerdadeiroOs operadores lógicos ajudam a juntar (de forma inclusiva ou exclusica) várias comparações. Assim, podemos cobrir lógicas como Isto E aquilo ou Aquilo OU o outro
verdadeiro E falso # Operador E (ambas as condições têm de ser verdadeiras)
verdadeiro OU falso # Operador OU (uma das condições tem de ser verdadeira)
NÃO verdadeiro # Operador NÃO (inversão do valor booleano)
# Exemplos:
imprime(verdadeiro E Falso) # Falso. Neste caso ambas as condições têm de ser 'verdadeiro' (Inclusivo)
imprime(verdadeiro OU Falso) # Verdadeiro. Neste caso Basta uma condição ser verdadeira para o seu resultado final ser VERDADEIRO (Exclusivo)
imprime(NAO Verdadeiro) # Falso. Neste caso pretende-se 'inverter' uma condiçãoO operador de contenção testa se um elemento faz parte de uma coleção (lista, mapa — chaves ou valores) ou se uma substring está presente numa string, produzindo um booleano.
elemento EM lista # Verifica se o elemento está na lista
# Exemplos:
lista = [1,2,3]
numero = 4
imprime(numero EM lista) # Falso. Pois o 4 não está contido na lista
imprime('Tóquio' EM 'Gosto de ir a Tóquio') # Verdadeiro# Operadores Lógicos com E, OU e NÃO
se idade >= 18 E isEstudante == verdadeiro:
imprime("Maior de idade e estudante.")
senao se idade < 18 OU isEstudante == falso:
imprime("Menor de idade ou não é estudante.")
senao:
imprime("Maior de idade.")
# Operador EM
lista = [1, 2, 3, 4, 5]
se 3 EM lista:
imprime("O número 3 está na lista.")
senao:
imprime("O número 3 não está na lista.")
# Operador NÃO
se NÃO isEstudante:
imprime("Não é estudante.")Entrada e Saída
- Entrada: obter dados de fontes externas — por exemplo teclado (prompt), ficheiros ou argumentos.
entrada("Qual o seu nome? ", nome) # exporta o que o utilizador insere para a variavel 'nome'
segredo("Password: ", password) # faz o mesmo que o 'entrada', porém oculta o que o utilizador insere (com '*****')- Saída: mostrar resultados ao utilizador.
imprime("Isto é para mostrar ao utilizador")- Leitura do teclado normalmente retorna uma string;
- Impressão converte valores para texto e escreve no ecrã ou num ficheiro.
- Sintaxe: usar
{expressão}dentro de uma string para inserir o valor resultante da expressão nessa posição. - Avalia a expressão e a converte para texto automaticamente.
- Permite inserir variáveis, chamadas de função ou operações (ex.: {idade + 1}).
- Vantagem: código mais limpo e legível comparado com concatenação manual.
Exemplos:
# Leitura do teclado (retorna string)
entrada("Qual é o teu nome?", nome)
entrada("Qual a tua idade?", idade)
# Saída com interpolação simples
imprime("Olá, {nome}! Tens {idade} anos.")
# Interpolação com expressão
imprime("No próximo ano terás {idade + 1} anos.")
# Escape de chaves (para mostrar { } literalmente)
imprime("Usa {expressao} para interpolação; exemplo: {idade}")
entrada("Digite o seu nome: ", nome)
segredo("Palavra-passe: ", password) # Entrada "segredo" oculta o valor digitado
imprime("Olá, {nome}")Controlo de Fluxo
Blocos condicionais são estruturas de controlo de fluxo que permitem que um programa tome decisões e execute diferentes escopos de código com base em condições específicas. Um bloco condicional avalia uma expressão (que resulta SEMPRE em verdadeiro ou falso) e executa diferentes ações dependendo do resultado da sua avaliação.
se [Condição]:
façaAlgo()
senao [outra Condição]:
façaAlgoDiferente()
senao:
façaOutraCoisa()Iterações (também chamadas de loops ou laços) são estruturas de controlo de fluxo que permitem repetir um escopo de código múltiplas vezes, sem precisar reescrevê-las. Uma iteração executa um conjunto de instruções repetidamente enquanto uma condição for verdadeira, ou para cada elemento de uma lista.
cada elemento em lista:
processeElemento(elemento)
continua() # Passa para o próximo ciclo
enquanto [condição]:
façaAlgo()
quebra() # Sai do cicloFunções
São a principal forma de modularizar programas e reutilizar código.
Declaração e chamada:
# Definição com retorno
funcao soma(a, b):
retorna a + b
r = soma(2, 3) # r = 5
# Definição sem retorno explícito (efeito/printing)
funcao cumprimenta(nome) {
imprime("Olá, {nome}!")
}
cumprimenta("Ana")Conceitos importantes
- Parâmetros e argumentos: parâmetros são nomes na definição; argumentos são os valores passados.
- Retorno: uma função pode usar
retornapara devolver um valor; - Escopo: variáveis definidas dentro da função são locais e não visíveis fora dela.
Recursão: funções podem chamar a si mesmas para resolver problemas divisíveis.
Exemplos avançados
# Recursão: fatorial
funcao fatorial(n):
se n <= 1:
retorna 1
retorna n * fatorial(n - 1)- Dá nomes descritivos às funções (verbo + complemento): ex.: calcular_imposto, ler_ficheiro.
- Mantém funções pequenas e com responsabilidade única.
- Documenta parâmetros e valores de retorno.
- Evita efeitos colaterais inesperados; valida entradas antes de operar.
# Função
funcao somar(a, b):
resultado = a + b
retorne resultado
resultado = somar(2,2) # 4Listas
- Indexação:
lista[i]dá o i-ésimo elemento (i começa em 0). índice -1 é o último. - Slicing / sublistas:
lista[start:end]inclui elementos desde start até end-1 (fim exclusivo).- Slices produzem normalmente uma nova lista (cópia).
- Para verificar pertença, usa
em(ex.:3 em lista).
Explicação linha a linha (com correções)
# Listas
minhaLista = [1, 2, 3, 4, 5]
primeiroElemento = minhaLista[0] # 1 (índice 0)
sublista = minhaLista[1:2] # [1, 2,3] <-- corrigido: end é inclusivo
ultimoElemento = minhaLista[-1] # 5 (índice -1)
sublistaAContarDoFim = minhaLista[1:-1]# [2, 3, 4] (start=1, end=-1 => até o penúltimo)
tamanhoDaLista = tamanho(minhaLista) # 5 (existem 5 elementos no array)
minhaLista.adicionar(6) # [1,2,3,4,5,6]starté incluído,endé incluido. Ex.: lista[0:2] → elementos 0, 1 e 2.- Se omites
start:lista[:end]começa em 0. Se omitesend:lista[start:]vai até ao fim. - Se omites ambos:
lista[:]faz uma cópia da lista inteira. O mesmo quelista - Índices fora de intervalo causam erro.
- Slices criam uma nova lista (mutações na sublista não alteram a original).
minhaLista = [1,2,3,4,5]
imprime(minhaLista[:2]) # [1, 2] (do início até índice 1)
imprime(minhaLista[2:]) # [3, 4, 5] (do índice 2 até ao fim)
sub = minhaLista[0:3]
sub[0] = 99 # altera só a sublista; não altera a original- Usa slice para extrair partes de uma lista sem escrever loops.
- Documenta se funções aceitam/pedem sublistas ou conjuntos (comportamento esperado).
Dicionários/Mapas
- Estruturas chave→valor: cada chave associa-se a um único valor. Exemplos de uso: representar um registo de pessoa, contador por categoria, cache, ou JSON.Criação e acesso:
# criar
Chave Valor
| |
v v
pessoa = ("nome"> "Ana", "idade"> 30}
vazio = ()
# acesso
nome = pessoa["nome"] # "Ana". Também podemos aceder, se soubermos a sua chave, `pessoa.nome`
# inserir / atualizar
pessoa["idade"] = 31
pessoa["cidade"] = "Porto"
# Métodos e operações comuns:
em: verificar se uma chave existe (ex.: "nome" em pessoa).
chaves(), valores(): iterar chaves, valores.
tamanho(): obter número de items.Exemplos de iteração e aninhamento
# iterar chaves
cada chave em pessoa.chaves():
imprime(chave)
# iterar pares
cada chave, valor em pessoa:
print("{chave}: {valor}")
# mapas aninhados
config = ("db"-> ("host"-> "localhost", "port"-> 5432))
host = config["db"]["host"]- As chaves são SEMPRE únicas.
- Usa comparações explícitas para evitar erros quando a chave não existir.
- Documenta formato esperado (quais chaves existem e tipos dos valores).
- Evita mutar um mapa enquanto o iteras; se precisares, itera sobre uma cópia das chaves.
- Confundir verificar existência de chave com verificar valor truthy (chave pode existir com valor null/false).
# contador usando mapa
contadores = ()
cada item em lista:
se item em contadores:
contadores[item] = contadores[item] + 1
continua() # Passa para o próximo ciclo
contadores[item] = 1
carro = ('marca' -> 'Opel', 'modelo' -> 'Astra')
# Aceder a valores
imprime(carro.marca)
imprime(carro['modelo'])
# Operações com Dicionários
# Adicionar uma nova chave-valor
carro['ano'] = 2020
# Iterar chaves e valores
cada chave, valor em carro:
imprime("Chave: {chave}, Valor: {valor}")
# Iterar apenas as chaves
cada chave em carro.chaves():
imprime(chave)
# Iterar apenas os valores
cada valor em carro.valores():
imprime(valor)Modelos
Modelos são o mecanismo da linguagem para definir tipos compostos com atributos (campos) e comportamentos (métodos).
Um modelo descreve a estrutura e as operações que as suas instâncias (objetos) terão.
- Para agrupar dados relacionados e operações sobre esses dados.
- Para representar entidades do domínio (pessoas, contas, formas, etc.).
- Para reutilizar e estender comportamentos através de herança.
modelo NomeDoModelo:
construtor(param1, param2, ...):
NomeDoModelo.campo1 = param1
NomeDoModelo.campo2 = param2
funcao nomeMetodo():
retorne "algum valor"
modeloinicia a definição.construtor(...)é invocado quando se cria uma instância; deve inicializar os campos.- Os campos são atribuídos usando a notação
NomeDoModelo.campo. funcaodefine métodos que podem aceder aos campos do modelo comNomeDoModelo.campo.
instancia = NomeDoModelo(arg1, arg2)
imprime(instancia.metodo())
- Modelo simples — Pessoa
modelo Pessoa:
construtor(nome, idade):
Pessoa.nome = nome
Pessoa.idade = idade
funcao apresentar():
retorne "Olá, o meu nome é {Pessoa.nome} e tenho {Pessoa.idade} anos."
- O construtor cria os campos
nomeeidade. - O método
apresentarusa esses campos para devolver uma string.
Uso:
alice = Pessoa("Alice", 30)
imprime(alice.apresentar())
# Saída esperada: Olá, o meu nome é Alice e tenho 30 anos.
- Inicialize todos os campos necessários no
construtor. - Use nomes de campos consistentes para evitar confusão entre pai e filho.
- Quando estender um modelo, confirme se precisa inicializar campos do pai no construtor do filho.
- Separe responsabilidades: mantenha métodos curtos e focados numa única ação.
- Esquecer de definir um campo no construtor e depois tentar usá-lo em métodos.
- Contar com inicialização automática do construtor do pai quando a linguagem não a faz.
- Usar nomes de campo idênticos sem intenção, levando a sobrescritas acidentais.
- Modelos encapsulam dados e comportamentos.
construtor(...)cria e inicializa campos.funcaodefine métodos que usamNomeDoModelo.campo.extendepermite herança; trate explicitamente a inicialização de campos herdados quando necessário.
modelo Pessoa:
construtor(nome, idade):
Pessoa.nome = nome
Pessoa.idade = idade
funcao apresentar():
retorne "Olá, o meu nome é {Pessoa.nome} e tenho {Pessoa.idade} anos."Métodos Auxiliares
aleatorio() # gera um número aleatório
aleatorio(1,10) #gera um número aleatório entre 1 e 10Como Executar um Programa em PseudoScript
- Para executar um programa, crie um ficheiro com nome descritivo em letras maiúsculas como INICIO.pseudoscript.
# INICIO.pseudoscript
importar src/programa como MeuPrograma
app = MeuPrograma.Programa()
app.start()- Sintaxe Simplificada: Sintaxe minimalista para facilitar o aprendizado.
- Tipagem Dinâmica: As variáveis podem ter o seu tipo modificado conforme o contexto.
- Estruturas de Dados Simples: Listas, dicionários e funções básicas.
- Orientação a Objetos: Conceitos básicos de OOP, com herança e métodos.