especificações atualizadas
This commit is contained in:
parent
08ead00116
commit
9a6470b321
1 changed files with 268 additions and 85 deletions
353
README.org
353
README.org
|
@ -1,108 +1,291 @@
|
||||||
* Linguagem Brisa
|
#+title: Linguagem Brisa
|
||||||
|
#+subtitle: Especificações
|
||||||
|
#+author: Blau Araujo
|
||||||
|
#+email: blau@debxp.org
|
||||||
|
|
||||||
** Tokens
|
* Visão geral
|
||||||
|
|
||||||
- Separadores de palavras: espaço, tabulação, /tokens/
|
Um código em Brisa tem esta aparência:
|
||||||
- Fim de linha: =\n=
|
|
||||||
- Comentário simples: =;=
|
|
||||||
- Comentário de bloco e /inline/: =;;; ... ;;;=
|
|
||||||
- Terminador de declarações: =.= (ponto)
|
|
||||||
- Operador de atribuição: =<=
|
|
||||||
- Operador de tipo de retorno: =>=
|
|
||||||
- Delimitador de indireção: =[IDENTIFICADOR/LISTA]=
|
|
||||||
|
|
||||||
** Tipos
|
|
||||||
|
|
||||||
*** Tipos inteiros com sinal
|
|
||||||
|
|
||||||
- =i8=: 1 byte
|
|
||||||
- =i16=: 2 bytes
|
|
||||||
- =i32=: 4 bytes (tipo padrão!)
|
|
||||||
- =i64=: 8 bytes
|
|
||||||
- =i128=: 16 bytes
|
|
||||||
|
|
||||||
*** Tipos inteiros sem sinal
|
|
||||||
|
|
||||||
- =u8=: 1 byte
|
|
||||||
- =u16=: 2 bytes
|
|
||||||
- =u32=: 4 bytes
|
|
||||||
- =u64=: 8 bytes
|
|
||||||
- =u128=: 16 bytes
|
|
||||||
|
|
||||||
*** Tipos de ponto flutuante (apenas com sinal)
|
|
||||||
|
|
||||||
- =f32=: 4 bytes
|
|
||||||
- =f64=: 8 bytes
|
|
||||||
- =f128=: 16 bytes
|
|
||||||
|
|
||||||
*** Tipo indeterminado
|
|
||||||
|
|
||||||
Não existe tipo indeterminado (=void=) na linguagem. Por exemplo, =NULL= é implementado como =(int64)0=.
|
|
||||||
|
|
||||||
*** Tipo booliano
|
|
||||||
|
|
||||||
=bool=: 1 byte
|
|
||||||
|
|
||||||
- Variáveis do tipo =bool= recebem apenas =true= ou =false=, respectivamente implementados como =1= e =0= do tipo =i8=.
|
|
||||||
- Expressões lógicas sempre resultam em valores =1= ou =0= do tipo =i32=, portanto não são =bool=.
|
|
||||||
- Ponteiros nulos (=NULL=), o terminador nulo (='\0'=) e inteiros de valor =0= sempre avaliam como falso, mas não são =bool=.
|
|
||||||
|
|
||||||
** Qualificadores e modificadores de escopo
|
|
||||||
|
|
||||||
- Constante: =const= -- Representa um dado imutável (=.rodata=?).
|
|
||||||
- Volátil: =volatile= -- Representa um dado de escopo global (=.data=?).
|
|
||||||
- Estático: =static= -- Representa um dado que mantém seu valor entre chamadas de função.
|
|
||||||
- Restrito: =restrict= -- Representa um endereço que só pode ser acessado por um nome de ponteiro.
|
|
||||||
|
|
||||||
** Variáveis
|
|
||||||
|
|
||||||
- Declaração: ~[QUALIFICADOR] [*][TIPO]:NOME.~
|
|
||||||
- Inicialização: ~[QUALIFICADOR] [*][TIPO]:NOME < VALOR~
|
|
||||||
- Atribuição: ~NOME < VALOR~
|
|
||||||
|
|
||||||
Exemplos:
|
|
||||||
|
|
||||||
#+begin_example
|
#+begin_example
|
||||||
:var < 42 ; declaração e inicialização da variável 'var' (tipo 'i32')
|
@doc
|
||||||
var < 10 ; atribuição do valor 10 à variável 'var'
|
Bloco de comentários...
|
||||||
i8:char. ; declaração da variável 'char' com o tipo 'i8' (1 byte)
|
@end
|
||||||
i8:char . ; espaços não fazem diferença após o nome da variável!
|
|
||||||
*:ptr < [var] ; declaração do ponteiro 'ptr' com o tipo *i32 e com o endereço de 'var'
|
; Declaração de uma função com retorno 'int' (inteiro 32 bits com sinal)...
|
||||||
[ptr] < 123 ; armazena o valor 123 no endereço apontado por 'ptr'
|
int:add42 (int:a) return(a + 42)
|
||||||
|
|
||||||
|
; Declaração de uma função com retorno 'nil' (símbolo sem associação de valor)...
|
||||||
|
nil:salve(str:name)
|
||||||
|
print("Salve, ", name, "!\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
; Função 'main' (ponto de entrada)...
|
||||||
|
int:main ()
|
||||||
|
int:x = 23 ; declaração de variável inicializada com expressão constante
|
||||||
|
int:y = x + 58 ; declaração de variável inicializada com avaliação da expressão
|
||||||
|
int:z ; declaração de variável não inicializada (valor 'nil')
|
||||||
|
|
||||||
|
@doc: outras sintaxes válidas...
|
||||||
|
int:a, b, c ; declaração de múltiplas variáveis de mesmo tipo não inicializadas
|
||||||
|
int:a = 1, b = 2, c = 3 ; declaração de múltiplas variáveis de mesmo tipo inicializadas
|
||||||
|
int:a = b = c ; variáveis 'a' e 'b' inicializadas com a avaliação de 'c' (que deve estar inicializada)
|
||||||
|
@end
|
||||||
|
|
||||||
|
salve("simpatia") ; chamada da função 'salve'
|
||||||
|
z = x + 58 ; operação de atribuição
|
||||||
|
print("z + 42 = ", add42(z), "\n") ; chamada da função 'add42' como argumento da função builtin 'print'
|
||||||
|
|
||||||
|
exit(0) ; função builtin 'exit' (opcional)
|
||||||
|
end
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
|
** Características principais do exemplo
|
||||||
|
|
||||||
|
*** Terminação de instruções
|
||||||
|
|
||||||
|
- Todas as instruções simples (uma linha) são delimitadas por quebras de linha;
|
||||||
|
- Linhas longas podem ser quebradas com contrabarras (~\~);
|
||||||
|
- Todas as instruções compostas (blocos) são delimitadas por um cabeçalho de bloco e pela palavra reservada ~end~;
|
||||||
|
- Se houver apenas uma instrução no bloco, o terminador ~end~ pode ser dispensado, desde que a instrução seja escrita na mesma linha do cabeçalho do bloco.
|
||||||
|
|
||||||
|
Os cabeçalhos de blocos podem ser:
|
||||||
|
|
||||||
|
- Assinaturas de funções;
|
||||||
|
- Estruturas de repetição ~for~, ~while~ e ~until~;
|
||||||
|
- Estruturas de decisão ~if~, ~elif~, ~else~;
|
||||||
|
- Estruturas de seleção ~select~, ~case~.
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
Nas estruturas ~if~ e ~select~, o terminador ~end~ só é utilizado após o bloco encabeçado pela última condição avaliada.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
*** Blocos de comentários
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
@doc
|
||||||
|
...
|
||||||
|
@end
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
- O cabeçalho ~@doc~ tem que iniciar a linha;
|
||||||
|
- Espaços e tabulações antes de ~@doc~ ou ~@end~ são ignorados;
|
||||||
|
- Tudo após ~@doc~ é ignorado, inclusive ocorrências de ~@doc~ antes do terminador ~@end~, ou de ~@end~, desde que não seja a única palavra na linha;
|
||||||
|
- A palavra ~@end~ tem que estar sozinha na linha para ser interpretado como um terminador de bloco de comentários;
|
||||||
|
- O cabeçalho ~@doc~ pode ser seguido que qualquer caractere, por exemplo:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
@doc: o que estamos comentando
|
||||||
|
...
|
||||||
|
@end
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Comentários inline
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
[...]; ...
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
Tudo após ~;~ é ignorado.
|
||||||
|
|
||||||
|
*** Declaração de identificadores
|
||||||
|
|
||||||
|
Todo identificador (nome de função ou de variável) deve ser declarado como:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
tipo[espaços]:[espaços]lista_de_nomes ; os espaços são ignorados na compilação
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
- Nomes seguidos de ~([lista de parâmetros])~ declaram /funções/;
|
||||||
|
- Nomes seguidos de ~= expressão~ identificam /variáveis inicializadas/;
|
||||||
|
- Nomes seguidos do fim da linha ou de uma vírgula (~,~) declaram /variáveis não inicializadas/;
|
||||||
|
- Espaços entre ~tipo~ e ~:~, ou entre ~:~ e o primeiro nome, são ignorados;
|
||||||
|
- A ~lista_de_nomes~ consiste de um ou mais nomes de /variáveis/ (inicializadas ou não) separadas por vírgulas (~,~);
|
||||||
|
- Todas as variáveis da lista são declaradas com o mesmo tipo;
|
||||||
|
- Variáveis não inicializadas avaliam ~nil~ (símbolo sem valor associado);
|
||||||
|
- Variáveis do tipo ~ptr~ identificam endereços e, se não inicializadas, avaliam ~NULL~ (ponteiro nulo).
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
Em Brisa, /variáveis/ são nomes que identificam dados em endereços na memória e /ponteiros/ são nomes
|
||||||
|
que identificam endereços de dados na memória.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
*Importante!* Para ser um nome válido, a palavra deve conter apenas a combinação de um ou mais
|
||||||
|
caracteres que casem com a expressão regular ~[A-Za-z_][0-9A-Za-z_]*~, ou seja, palavras iniciadas
|
||||||
|
com caracteres alfabéticos ou sublinhado (~_~) seguidos de zero ou mais caracteres alfanuméricos
|
||||||
|
ou sublinhado.
|
||||||
|
|
||||||
** Expressões constantes
|
** Expressões constantes
|
||||||
|
|
||||||
Sintaxe: =[(TIPO)]EXPRESSÃO=
|
São palavras que representam valores literais associados a tipos de dados:
|
||||||
|
|
||||||
Sem especificação de tipo...
|
- *Inteiros decimais*: ~[+-]?(0|[1-9][0-9]*)~ (~0~, ~42~, ~-123~, etc)
|
||||||
|
- *Inteiros hexadecimais:* ~0[Xx][0-9A-Fa-f]+~ (~0x0a~, ~0xffcb~, etc)
|
||||||
|
- *Inteiros octais:* ~[+-]?0[Oo][1-7]+~ (~0o1~, ~0o123~, ~-0o42~, etc)
|
||||||
|
- *Inteiros binários:* ~0[Bb][0-1]~ (~0b0110~, ~0b10001010~, etc)
|
||||||
|
- *Ponto flutuante:* ~1.23~, ~3.4e23~...
|
||||||
|
- *Lista de caracteres:* ~'lista de caracteres imprimíveis ou escapados'~ (sem terminação nula)
|
||||||
|
- *Strings:* ~"lista de caracteres imprimíveis ou escapados"~ (inclui terminação nula)
|
||||||
|
- *Boolianos:* ~true~ (byte ~0x01~) e ~false~ (byte ~0x00~)
|
||||||
|
|
||||||
- ='CHAR'= são sempre =i8=;
|
*Importante!*
|
||||||
- Notações numéricas inteiras são sempre =i32=;
|
|
||||||
- Notações de ponto flutuante e frações são sempre =f64=.
|
O sinal de representações hexadecimais e binárias depende do tipo associado à variável. No entanto,
|
||||||
|
por padrão, essas representações serão tratadas como ~unsigned int~ quando utilizadas em expressões:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
int:a = 0xff ; avalia -1 (em 32 bits)
|
||||||
|
u32:b = 0xff ; avalia 255 (em 32 bits)
|
||||||
|
int:c
|
||||||
|
|
||||||
|
c = 5 + 0xff ; 5 + 255 = 300
|
||||||
|
c += a ; 300 + (-1) = 299
|
||||||
|
c += b ; 299 + 255 = 554
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
Os tipos ~int~ e ~i32~ são equivalentes, ou seja, são inteiros de 32 bits com sinal.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
** Especificadores de tipos
|
||||||
|
|
||||||
*** Inteiros
|
*** Inteiros
|
||||||
|
|
||||||
- =10=: o mesmo que =(i32)10=
|
- ~int~ ou ~i32~: inteiros de 32 bits com sinal;
|
||||||
- Qualquer outro tipo inteiro: =(tipo)número=
|
- ~u32~: inteiros de 32 bits sem sinal;
|
||||||
|
- ~i64~: inteiros de 64 bits com sinal;
|
||||||
|
- ~u64~: inteiros de 64 bits sem sinal;
|
||||||
|
- ~byte~ ou ~i8~: inteiro de 8 bits com sinal;
|
||||||
|
- ~u8~: inteiro de 8 bits sem sinal;
|
||||||
|
- ~word~ ou ~i16~: inteiro de 16 bits com sinal;
|
||||||
|
- ~u16~: inteiro de 16 bits sem sinal;
|
||||||
|
|
||||||
*** Bytes (i8)
|
*** Endereços
|
||||||
|
|
||||||
- Representação de caracteres: ='\n'= (valor ASCII do caractere '\n' - byte 0x0a)
|
- ~ptr~: define a variável como um ponteiro (endereços de 64 bits);
|
||||||
- Outras representações numéricas requerem modelagem =(i8)=
|
- ~str~: mesmo que um ponteiro para um vetor de bytes na memória;
|
||||||
|
- ~arr~: mesmo que um ponteiro para uma tabela (vetor associativo de dados de tipos diferentes);
|
||||||
|
- ~vec~: mesmo que um ponteiro para um vetor (vetor indexado de dados de mesmo tipo);
|
||||||
|
|
||||||
*** Ponto flutuante
|
*Nota sobre ponteiros não inicializados:*
|
||||||
|
|
||||||
- =5.0=: o mesmo que =(f64)5.0=
|
Todos os tipos relacionados a endereços avaliam ~NULL~ quando não inicializados.
|
||||||
- =20 / 4=: o mesmo que =(f64)5.0=
|
|
||||||
- Qualquer outro tipo de ponto flutuante: =(tipo)representação=
|
|
||||||
|
|
||||||
*** Cadeias de bytes (vetores do tipo i8)
|
*Nota sobre tabelas e vetores:*
|
||||||
|
|
||||||
- =['c', 'a', 's', 'a', '\n', '\0']= (avalia o endereço do primeiro byte)
|
Em Brisa, /arrays/ (tabelas) são coleções dinâmicas e associativas de elementos de tipos diferentes,
|
||||||
- ='casa\n\0'=: o mesmo que =['c', 'a', 's', 'a', '\n', '\0']= (avalia o endereço do primeiro byte)
|
enquanto /vetores/ são listas dinâmicas de elementos de um mesmo tipo, o que é determinado pelo tipo
|
||||||
- ="casa\n"=: o mesmo que =['c', 'a', 's', 'a', '\', 'n', '\0']= (avalia o endereço do primeiro byte)
|
do primeiro elemento.
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
arr:tabela = { "banana", "qtd" 10, "unidade" "quilo" }
|
||||||
|
|
||||||
|
@doc: o acesso pode ser por chave ou índice...
|
||||||
|
tabela["0"] = "banana" -> tabela[0] = 0
|
||||||
|
tabela["qtd"] = 10 -> tabela[1] = "preço"
|
||||||
|
tabela["unidade"] = "quilo" -> tabela[2] = "unidades"
|
||||||
|
@end
|
||||||
|
|
||||||
|
vec:lista = { 123, 42, 23 }
|
||||||
|
|
||||||
|
@doc: acesso apenas pelos índices...
|
||||||
|
lista[0] = 123
|
||||||
|
lista[1] = 42
|
||||||
|
lista[2] = 23
|
||||||
|
@end
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** O tipo especial 'nil'
|
||||||
|
|
||||||
|
A palavra reservada ~nil~ representa um endereço fixo e único na memória sem um dado associado. Sua
|
||||||
|
avaliação depende do contexto:
|
||||||
|
|
||||||
|
- Expressões aritméticas: avalia ~0~;
|
||||||
|
- Expressões boolianas: avalia ~false~;
|
||||||
|
- Contexto de strings: representa uma string vazia (byte ~0x00~);
|
||||||
|
- Declarações de variáveis: expressa que a variável não foi inicializada;
|
||||||
|
- Retornos de funções: expressa que a função não tem retorno.
|
||||||
|
|
||||||
|
** Funções builtin
|
||||||
|
|
||||||
|
A biblioteca padrão da linguagem Brisa (~librisa~) oferece vários construtores de linguagem na forma
|
||||||
|
de funções /builtin/, como:
|
||||||
|
|
||||||
|
- ~echo(str:string, ...)~: imprime, na saída padrão, todos os argumentos interpolados por um espaço e com
|
||||||
|
uma quebra de linha ao final (os terminadores nulos são removidos).
|
||||||
|
|
||||||
|
- ~print(str:string, ...)~: imprime, na saída padrão, o resultado da concatenação de todos os argumentos
|
||||||
|
(não inclui a quebra de linha final).
|
||||||
|
|
||||||
|
- ~strlen(str:string)~: retorna a quantidade de caracteres de uma string (desconta o terminador nulo)
|
||||||
|
|
||||||
|
- ~exit(byte:status)~: termina o programa com o estado de término ~status~.
|
||||||
|
|
||||||
|
- ~return(expressão)~: utilizada para retornar um valor do tipo especificado na declaração da função.
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
Em todas as funções /builtin/ que trabalham com strings, é possível passar expressões como argumentos,
|
||||||
|
inclusive valores numéricos retornados por funções, porque a conversão para string será feita em tempo
|
||||||
|
de execução.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
** Declaração de funções
|
||||||
|
|
||||||
|
Não existe uma separação entre a declaração e a definição de funções: funções são declaradas no
|
||||||
|
mesmo momento em que são definidas, o que pode ser feito de duas formas:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
; Declaração em bloco...
|
||||||
|
tipo:nome (lista_de_parâmetros)
|
||||||
|
instruções...
|
||||||
|
[return(expressão)]
|
||||||
|
end
|
||||||
|
|
||||||
|
; Declaração em linha...
|
||||||
|
tipo:nome (lista_de_parâmetros) uma_instrução
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
- Na declaração em bloco, a primeira instrução até pode ser escrita na mesma linha do cabeçalho da função, mas isso pode tornar o código confuso.
|
||||||
|
- A função /builtin/ ~return~ é obrigatória em funções com retorno diferente de ~nil~.
|
||||||
|
|
||||||
|
*** Delimitadores de argumentos
|
||||||
|
|
||||||
|
Os parêntesis da lista de parâmetros servem como delimitadores de blocos e, portanto, possibilitam a escrita de argumentos em várias linhas nas chamadas de funções:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
; Isso é válido...
|
||||||
|
print(
|
||||||
|
"Maria ",
|
||||||
|
"tinha ",
|
||||||
|
"um carneirinho."
|
||||||
|
)
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*Importante!* Isso é válido apenas no contexto de chamadas de funções -- em expressões, os parêntesis são operadores de precedência.
|
||||||
|
|
||||||
|
*** Funções anônimas (closures)
|
||||||
|
|
||||||
|
É possível criar funções anônimas com os nomes reservados ~function~, ~func~ ou ~fun~ (só pela diversão):
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
; função anônima em bloco...
|
||||||
|
fun[c[tion]] (parâmetros)
|
||||||
|
instruções...
|
||||||
|
[return(expressão)]
|
||||||
|
end
|
||||||
|
|
||||||
|
; função anônima em linha...
|
||||||
|
tipo:fun[c[tion]] (parâmetros) uma_instrução
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
Entretanto, elas só podem ser criadas em atribuições de variáveis ou como argumentos de outras funções:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
int:x
|
||||||
|
|
||||||
|
x = fun(int:num) return(num + 42) ; o tipo do retorno é o mesmo da variável 'x'
|
||||||
|
|
||||||
|
echo(x(42)) ; imprime '84'
|
||||||
|
echo(x(81)) ; imprime '123'
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue