Difference between revisions of "Compiladores/Projecto de Compiladores/Projecto 2020-2021/Manual de Referência da Linguagem FIR (rascunho)"

From Wiki**3

< Compiladores‎ | Projecto de Compiladores
(Exemplos)
 
(108 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{PRJCompiladoreAvisosEN20202021}}
+
#REDIRECT [[Compiladores/Projecto de Compiladores/Projecto 2020-2021/Manual de Referência da Linguagem FIR]]
<!--{{PRJCompiladoreAvisosEE20202021}}-->
 
{{PRJCOMandatory20202021}}
 
{{TOCright}}
 
<font color="red">'''EM PREPARAÇÃO'''</font>
 
 
 
'''FIR''' é uma linguagem imperativa. Este manual apresenta de forma intuitiva as características da linguagem: [[#Tipos de Dados|tipos de dados]]; [[#Manipulação de Nomes|manipulação de nomes]]; [[#Convenções Lexicais|convenções lexicais]]; [[#Gramática|estrutura/sintaxe]]; [[#Funções|especificação das funções]]; [[#Instruções|semântica das instruções]]; [[#Expressões|semântica das expressões]]; e, finalmente, [[#Exemplos|alguns exemplos]].
 
 
 
= Tipos de Dados =
 
 
 
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 5 tipos de dados (4 deles declaráveis explicitamente), todos compatíveis com a [https://en.wikipedia.org/wiki/C_(programming_language) linguagem C], e com alinhamento em memória sempre a 32 bits:
 
 
 
* Tipos numéricos: os '''inteiros''', em [https://en.wikipedia.org/wiki/Two%27s_complement complemento para dois], ocupam 4 bytes; os '''reais''', em [https://en.wikipedia.org/wiki/Floating_point vírgula flutuante], ocupam 8 bytes ([https://en.wikipedia.org/wiki/IEEE_floating_point IEEE 754]).
 
* As '''cadeias de caracteres''' são vectores de caracteres terminados por [https://en.wikipedia.org/wiki/ASCII ASCII] NULL ('''0x00''', '''\0'''). Variáveis e literais deste tipo só podem ser utilizados em atribuições, impressões, ou como argumentos/retornos de funções.
 
* Os '''ponteiros''' representam endereços de objectos e ocupam 4 bytes. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado.
 
 
 
Os tipos de dados podem ser manipulados individualmente, usando-se expressões desse tipo, ou em conjuntos (tipo estruturado) correspondentes a sequências de expressões (tuplos). O uso de tuplos é limitado a algumas situações (ver abaixo).
 
 
 
Os tipos suportados por cada operador e a operação a realizar são indicados na [[#Expressões|definição das expressões]].
 
 
 
= Manipulação de Nomes =
 
 
 
Os nomes ([[#Identificadores|identificadores]]) correspondem a variáveis e funções. Nos pontos que se seguem, usa-se o termo entidade para as designar indiscriminadamente, explicitando-se quando a descrição for válida apenas para um subconjunto.
 
 
 
== Espaço de nomes e visibilidade dos identificadores ==
 
 
 
O espaço de nomes global é único, pelo que um nome utilizado para designar uma entidade num dado contexto não pode ser utilizado para designar outras (ainda que de natureza diferente).
 
 
 
Os identificadores são visíveis desde a declaração até ao fim do alcance: ficheiro (globais) ou função (locais). A reutilização de identificadores em contextos inferiores encobre declarações em contextos superiores: redeclarações locais podem encobrir as globais até ao fim de uma função. Não é possível importar ou definir símbolos globais nos contextos das funções (ver [[#Símbolos globais|símbolos globais]]).
 
 
 
Não é possível definir funções dentro de blocos.
 
 
 
== Validade das variáveis ==
 
 
 
As entidades globais (declaradas fora de qualquer função), existem durante toda a execução do programa. As variáveis locais a uma função existem apenas durante a sua execução. Os argumentos formais são válidos enquanto a função está activa.
 
 
 
= Convenções Lexicais =
 
 
 
Para cada grupo de elementos lexicais (''tokens''), considera-se a maior sequência de caracteres constituindo um elemento válido.
 
 
 
== Caracteres brancos ==
 
 
 
São considerados separadores e não representam nenhum elemento lexical: '''mudança de linha''' ASCII LF ('''0x0A''', '''\n'''), '''recuo do carreto''' ASCII CR ('''0x0D''', '''\r'''), '''espaço''' ASCII SP ('''0x20''') e '''tabulação horizontal''' ASCII HT ('''0x09''', '''\t''').
 
 
 
== Comentários ==
 
 
 
Existem dois tipos de comentários, que também funcionam como elementos separadores:
 
* '''explicativos''' -- começam com '''//''' e acabam no fim da linha; e
 
* '''operacionais''' -- começam com '''/*''' e terminam com '''*/''', podendo estar aninhados.
 
 
 
Se as sequências de início fizerem parte de uma cadeia de caracteres, não iniciam um comentário (ver definição das [[#Cadeias de caracteres|cadeias de caracteres]]).
 
 
 
== Palavras chave ==
 
 
 
As palavras indicadas de seguida estão reservados (palavras chave), não podendo ser utilizadas como identificadores. Estas palavras têm de ser escritas exactamente como indicado:
 
 
 
  auto int real string ptr public require sizeof input nullptr
 
  procedure break continue return if then elif else for do write writeln
 
 
 
O identificador '''og''', embora não reservado, quando refere uma função, corresponde à [[#Função principal e execução de programas|função principal]], devendo ser declarado público.
 
 
 
== Tipos ==
 
 
 
Os seguintes elementos lexicais designam tipos em declarações (ver [[#Gramática|gramática]]): '''int''' (inteiro), '''real''' (real), '''string''' (cadeia de caracteres), '''auto''' (tipo inferido a partir do valor inicial), '''ptr''' (ponteiros). Ver [[#Gramática|gramática]].
 
 
 
O tipo especial '''auto''' é utilizado para indicar que o tipo da variável ou do retorno da função deve ser inferido a partir do tipo do seu valor inicial. Quando aplicado a uma função, implica que o tipo de retorno deve ser inferido a partir da expressão que é usada na instrução '''return''' (se existirem múltiplas, todas devem concordar no tipo a retornar). Este tipo pode ser usado com uma sequência de identificadores, declarando um tuplo. Os tipos dos vários campos do tuplo são inferidos das posições correspondentes do valor inicial: pode ser uma sequência de expressões ou outro tuplo. Em ambos os casos, o número de elementos deve ser o mesmo que o dos identificadores declarados (i.e., mesmo que seja usada uma variável ou o retorno de uma função como valor inicial para as variáveis declaradas, essas expressões devem ser tuplos da mesma dimensão).  Tuplos com um único elemento são idênticos ao tipo que contêm.
 
 
 
O tipo '''auto''' pode ser utilizado para definir ponteiros genéricos (como '''void*''' em C/C++), compatíveis com todos os tipos de ponteiros. São ainda o único tipo de ponteiro convertível para um número inteiro (o valor do inteiro é o valor do endereço de memória). O nível de aninhamento é irrelevante neste caso, i.e., '''ptr<auto>''' designa o mesmo tipo que '''ptr<ptr<...ptr<auto>...>>'''.
 
 
 
== Operadores de expressões ==
 
 
 
São considerados operadores os elementos lexicais apresentados na [[#Expressões|definição das expressões]].
 
 
 
== Delimitadores e terminadores ==
 
 
 
Os seguintes elementos lexicais são delimitadores/terminadores: ''',''' (vírgula), ''';''' (ponto e vírgula), e '''(''' e ''')''' (delimitadores de expressões).
 
 
 
== Identificadores (nomes) ==
 
 
 
São iniciados por uma letra, seguindo-se 0 (zero) ou mais letras, dígitos ou '''_''' (sublinhado). O comprimento do nome é ilimitado e dois nomes são distintos se houver alteração de maiúscula para minúscula, ou vice-versa, de pelo menos um carácter.
 
 
 
== Literais ==
 
 
 
São notações para valores constantes de alguns tipos da linguagem (não confundir com constantes, i.e., identificadores que designam elementos cujo valor não pode ser alterado durante a execução do programa).
 
 
 
=== Inteiros ===
 
 
 
Um literal inteiro é um número não negativo. Uma constante inteira pode, contudo, ser negativa: números negativos são construídos pela aplicação do operador de negação aritmética unária ('''-''') a um literal positivo.
 
 
 
Literais inteiros decimais são constituídos por sequências de 1 (um) ou mais dígitos de '''0''' a '''9'''. <!--, em que o primeiro dígito não é '''0''' (zero), excepto no caso do número 0 (zero). Neste caso, é composto apenas pelo dígito '''0''' (zero) (em qualquer base).-->
 
<!-- Um literal inteiro em octal começa sempre pelo dígito \verb|0| (zero), sendo seguido de um ou mais dígitos de \verb|0| a \verb|7| (note-se que \verb|09| é um literal octal inválido com valor \verb|011|). Exemplo: \verb|007|.-->
 
 
 
Literais inteiros hexadecimais começam sempre com a sequência '''0x''', seguida de um ou mais dígitos de '''0''' a '''9''' ou de '''a''' a '''f''' (sem distinguir maiúsculas de minúsculas). As letras de '''a''' a '''f''' representam os valores de 10 a 15 respectivamente. Exemplo: '''0x07'''.
 
 
 
<!-- Um literal inteiro em binário começa sempre pela sequência \verb|0b|, sendo seguido de um ou mais digitos \verb|0| ou \verb|1|.  -->
 
Se não for possível representar o literal inteiro na máquina, devido a um overflow, deverá ser gerado um erro lexical.
 
 
 
=== Reais em vírgula flutuante ===
 
 
 
Os literais reais positivos são expressos tal como em C (apenas é suportada a base 10).
 
 
 
Não existem literais negativos (números negativos resultam da aplicação da operação de negação unária).
 
 
 
Um literal sem '''.''' (ponto decimal) nem parte exponencial é do tipo inteiro.
 
 
 
Se não for possível representar o literal real na máquina, devido a um overflow, deverá ser gerado um erro lexical.
 
 
 
Exemplos: '''3.14''', '''1E3''' = 1000 (número inteiro representado em virgula flutuante). '''12.34e-24''' = 12.34 x 10<sup>-24</sup> (notação cientifica).
 
 
 
=== Cadeias de caracteres ===
 
 
 
As cadeias de caracteres são delimitadas por aspas ('''"''') e podem conter quaisquer caracteres, excepto ASCII NULL ('''0x00''' '''\0'''). Nas cadeias, os delimitadores de comentários não têm significado especial. Se for escrito um literal que contenha '''\0''', então a cadeia termina nessa posição. Exemplo: '''"ab\0xy"''' tem o mesmo significado que '''"ab"'''.
 
 
 
É possível designar caracteres por sequências especiais (iniciadas por '''\'''), especialmente úteis quando não existe representação gráfica directa. As sequências especiais correspondem aos caracteres ASCII LF, CR e HT ('''\n''', '''\r''' e '''\t''', respectivamente), aspa ('''\"'''), barra ('''\\'''), ou a quaisquer outros especificados através de 1 ou 2 digitos hexadecimais (e.g. '''\0a''' ou apenas '''\a''' se o carácter seguinte não representar um dígito hexadecimal).
 
 
 
Elementos lexicais distintos que representem duas ou mais cadeias consecutivas são representadas na linguagem como uma única cadeia que resulta da concatenação.
 
 
 
Exemplos:
 
* '''"ab"''' '''"cd"''' é o mesmo que '''"abcd"'''.
 
* '''"ab" /* comentário com "cadeia de caracteres falsa" */ "cd"''' é o mesmo que '''"abcd"'''.
 
 
 
=== Ponteiros ===
 
 
 
O único literal admissível para ponteiros é indicado pela palavra reservada '''nullptr''', indicando o ponteiro nulo.
 
 
 
= Gramática =
 
 
 
A gramática da linguagem está resumida abaixo. Considerou-se que os elementos em tipo fixo são literais; que os parênteses curvos agrupam elementos: <math>(</math> e <math>)</math>; que elementos alternativos são separados por uma barra vertical: <math>|</math>; que elementos opcionais estão entre parênteses rectos: <math>[</math> e <math>]</math>; que os elementos que se repetem zero ou mais vezes estão entre <math>\langle</math> e <math>\rangle</math>. Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses).
 
 
 
{|
 
! style="width: 140px; font-weight: normal;" | ''ficheiro''
 
! style="width: 50px; font-weight: normal;" | <math>\rightarrow</math>
 
| ''declaração'' <math>\langle</math> ''declaração'' <math>\rangle</math>
 
|-
 
! style="width: 150px; font-weight: normal;" | ''declaração''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| ''variável'' ''';''' <math>|</math> ''função'' <math>|</math> ''procedimento''
 
|-
 
! style="width: 50px; font-weight: normal;" | ''variável''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| <math>[</math> '''public''' <math>|</math> '''require''' <math>]</math> ''tipo'' ''identificador'' <math>[</math> '''=''' ''expressão'' <math>]</math>
 
|-
 
! style="width: 50px; font-weight: normal;" |
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| <math>[</math> '''public''' <math>]</math> '''auto''' ''identificadores'' '''='''  ''expressões''
 
|-
 
! style="width: 50px; font-weight: normal;" | ''função''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| <math>[</math> '''public''' <math>|</math> '''require''' <math>]</math> <math>(</math> ''tipo'' <math>|</math> '''auto''' <math>)</math> ''identificador'' '''(''' <math>[</math> ''variáveis'' <math>]</math> ''')''' <math>[</math> ''bloco'' <math>]</math>
 
|-
 
! style="width: 50px; font-weight: normal;" | ''procedimento''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| <math>[</math> '''public''' <math>|</math> '''require''' <math>]</math> '''procedure''' ''identificador'' '''(''' <math>[</math> ''variáveis'' <math>]</math> ''')''' <math>[</math> ''bloco'' <math>]</math>
 
|-
 
! style="width: 50px; font-weight: normal;" | ''identificadores''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| ''identificador'' <math>\langle</math> ''',''' ''identificador'' <math>\rangle</math>
 
|-
 
! style="width: 50px; font-weight: normal;" | ''expressões''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| ''expressão'' <math>\langle</math> ''',''' ''expressão'' <math>\rangle</math>
 
|-
 
! style="width: 50px; font-weight: normal;" | ''variáveis''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| ''variável'' <math>\langle</math> ''',''' ''variável'' <math>\rangle</math>
 
|-
 
! style="width: 50px; font-weight: normal;" | ''tipo''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''int''' <math>|</math> '''real''' <math>|</math> '''string''' <math>|</math> '''ptr<''' <math>(</math> ''tipo'' <math>|</math> '''auto''' <math>)</math> '''>'''
 
|-
 
! style="width: 50px; font-weight: normal;" | ''bloco''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''{''' <math>\langle</math> ''declaração'' <math>\rangle</math> <math>\langle</math> ''instrução'' <math>\rangle</math> '''}'''
 
|-
 
! style="width: 50px; font-weight: normal;" | ''instrução''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| ''expressão'' ''';''' <math>|</math> '''write''' ''expressões'' ''';''' <math>|</math> '''writeln''' ''expressões'' ''';'''
 
|-
 
! style="width: 50px; font-weight: normal;" |
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''break''' <math>|</math> '''continue''' <math>|</math> '''return''' <math>[</math> ''expressões'' <math>]</math> ''';'''
 
|-
 
! style="width: 50px; font-weight: normal;" |
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| ''instrução-condicional'' <math>|</math> ''instrução-de-iteração'' <math>|</math> ''bloco''
 
|-
 
! style="width: 50px; font-weight: normal;" | ''instrução-condicional''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''if''' ''expressão'' '''then''' ''instrução''
 
|-
 
! style="width: 50px; font-weight: normal;" |
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''if''' ''expressão'' '''then''' ''instrução'' <math>\langle</math>  '''elif''' ''expressão'' '''then''' ''instrução'' <math>\rangle</math> <math>[</math> '''else''' ''instrução'' <math>]</math>
 
|-
 
! style="width: 50px; font-weight: normal;" | ''instrução-de-iteração''
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''for''' <math>[</math> ''variáveis'' <math>]</math> ''';''' <math>[</math> ''expressões'' <math>]</math> ''';''' <math>[</math> ''expressões'' <math>]</math> '''do''' ''instrução''
 
|-
 
! style="width: 50px; font-weight: normal;" |
 
! style="width: 50px; font-weight: normal;" |<math>\rightarrow</math>
 
| '''for''' <math>[</math> ''expressões'' <math>]</math> ''';''' <math>[</math> ''expressões'' <math>]</math> ''';''' <math>[</math> ''expressões'' <math>]</math> '''do''' ''instrução''
 
|}
 
 
 
== Tipos, identificadores, literais e definição de expressões ==
 
 
 
Algumas definições foram omitidas da gramática: [[#Tipos de dados|tipos de dados]], ''identificador'' (ver [[#Identificadores|identificadores]]), ''literal'' (ver [[#Literais|literais]]); ''expressão'' (ver [[#Expressões|expressões]]).
 
 
 
== Left-values ==
 
 
 
Os ''left-values'' são posições de memória que podem ser modificadas (excepto onde proibido pelo tipo de dados). Os elementos de uma expressão que podem ser utilizados como ''left-values'' encontram-se individualmente identificados na [[#Expressões|semântica das expressões]].
 
 
 
== Ficheiros ==
 
 
 
Um ficheiro é designado por principal se contiver a [[#Função principal e execução de programas|função principal]] (a que inicia o programa).
 
 
 
== Declaração de variáveis ==
 
 
 
Uma declaração de variável indica sempre um [[#Tipos de dados|tipo de dados]] e um [[#Manipulação de nomes|identificador]].
 
 
 
Exemplos:
 
* Inteiro: '''int i'''
 
* Real: '''real r'''
 
* Cadeia de caracteres: '''string s'''
 
* Ponteiro para inteiro: '''ptr<int> p1''' (equivalente a '''int*''' em C)
 
* Ponteiro para real: '''ptr<real> p2''' (equivalente a '''double*''' em C)
 
* Ponteiro para cadeia de caracteres: '''ptr<string> p3''' (equivalente a '''char**''' em C)
 
* Ponteiro para ponteiro para inteiro: '''<nowiki>ptr<ptr<int>> p4</nowiki>''' (equivalente a '''int**''' em C)
 
* Ponteiro genérico: '''<nowiki>ptr<auto> p5</nowiki>''' (equivalente a '''void*''' em C)
 
 
 
== Símbolos globais ==
 
 
 
Por omissão, os símbolos são privados a um módulo, não podendo ser importados por outros módulos.
 
 
 
A palavra chave '''public''' permite declarar um identificador como público, tornando-o acessível a partir de outros módulos.
 
 
 
A palavra chave '''require''' (opcional para funções) permite declarar num módulo entidades definidas em outros módulos. As entidades não podem ser inicializadas nestas declarações. <!--Não é possível utilizar '''require''' em declarações que utilizem a palavra chave '''auto''' (excepto nos casos em que se use '''ptr<auto>''').-->
 
 
 
Exemplos:
 
* Declarar variável privada ao módulo: '''real pi = 22'''
 
* Declarar variável pública: '''public real pi = 22'''
 
* Usar definição externa: '''require real pi'''
 
 
 
== Inicialização ==
 
 
 
Quando existe, é uma expressão que segue o sinal '''=''' ("igual"): inteira, real, ponteiro. Entidades reais podem ser inicializadas por expressões inteiras (conversão implícita). A expressão de inicialização deve ser um literal se a variável for global.
 
 
 
As [[#Cadeias de caracteres|cadeias de caracteres]] são (possivelmente) inicializadas com uma lista não nula de valores sem separadores. <!--Estes valores são sempre constantes, independentemente de o identificador que as designa ser constante ou não.-->
 
 
 
Exemplos:
 
* Inteiro (literal): '''int i = 3'''
 
* Inteiro (expressão): '''int i = j+1'''
 
* Real (literal): '''real r = 3.2'''
 
* Real (expressão): '''real r = i - 2.5 + f(3)'''
 
* Cadeia de caracteres (literal): '''string s = "olá"'''
 
* Cadeia de caracteres (literais): '''string s = "olá" "mãe"'''
 
* Ponteiro (literal): '''<nowiki>ptr<ptr<ptr<real>>></nowiki> p = nullptr'''
 
* Ponteiro (expressão): '''ptr<real> p = q + 1'''
 
* Ponteiro (genérico): '''ptr<auto> p = q'''
 
* Tuplo (simples): '''auto p = 2.1'''
 
* Tuplo (função): '''auto a, b, c, d = f(1)'''
 
* Tuplo (sequência): '''auto i, j, k = 1, 2, g + 1'''
 
 
 
= Funções =
 
 
 
Uma função permite agrupar um conjunto de instruções num corpo, executado com base num conjunto de parâmetros (os argumentos formais), quando é invocada a partir de uma expressão.
 
 
 
== Declaração ==
 
 
 
As funções são sempre designadas por identificadores constantes precedidos do tipo de dados devolvido pela função. Se a função não devolver um valor, é declarada como procedimento, usando-se a palavra chave '''procedure''' para o indicar.
 
 
 
As funções que recebam argumentos devem indicá-los no cabeçalho. Funções sem argumentos definem um cabeçalho vazio. Não é possível aplicar os qualificadores de exportação/importação '''public''' ou '''require''' (ver [[#Símbolos globais|símbolos globais]]) às declarações dos argumentos de uma função. Não é possível especificar valores iniciais (valores por omissão) para argumentos de funções. O tipo '''auto''' não pode ser usado para declarar tipos de argumentos (excepto para definição de ponteiros genéricos).
 
 
 
A declaração de uma função sem corpo é utilizada para tipificar um identificador exterior ou para efectuar declarações antecipadas (utilizadas para pré-declarar funções que sejam usadas antes de ser definidas, por exemplo, entre duas funções mutuamente recursivas). Caso a declaração tenha corpo, define-se uma nova função (neste caso, não pode utilizar-se a palavra chave '''require''').
 
 
 
== Invocação ==
 
 
 
A função só pode ser invocada através de um identificador que refira uma função previamente declarada ou definida.<!-- O identificador especial '''@''' pode ser utilizado para invocar recursivamente a função actual.-->
 
 
 
Se existirem argumentos, na invocação da função, o identificador é seguido de uma lista de expressões delimitadas por parênteses curvos. Esta lista é uma sequência, possivelmente vazia, de expressões separadas por vírgulas. O número e tipo de parâmetros actuais deve ser igual ao número e tipo dos parâmetros formais da função invocada. A ordem dos parâmetros actuais deverá ser a mesma dos argumentos formais da função a ser invocada.
 
 
 
De acordo com a convenção Cdecl, a função chamadora coloca os argumentos na pilha e é responsável pela sua remoção, após o retorno da chamada. Assim, os parâmetros actuais devem ser colocados na pilha pela ordem inversa da sua declaração (i.e., são avaliados da direita para a esquerda antes da invocação da função e o resultado passado por cópia/valor). O endereço de retorno é colocado no topo da pilha pela chamada à função.
 
 
 
Quando o tipo a retornar pela função a chamar não é primitivo (i.e., é um tuplo), o chamador deve reservar uma zona de memória compatível com o tipo de retorno e passá-la por ponteiro à função chamada como o seu primeiro argumento (ver abaixo).
 
 
 
== Corpo ==
 
 
 
O corpo de uma função consiste num bloco que pode ter declarações (opcionais) seguidas de instruções (opcionais). Uma função sem corpo é uma declaração e é considerada indefinida.
 
 
 
Não é possível aplicar as palavras chave '''public''' ou '''require''' (ver [[#Símbolos globais|símbolos globais]]) dentro do corpo de uma função.
 
 
 
Uma instrução '''return''' causa a interrupção imediata da função, assim como o retorno dos valores indicados como argumento da instrução. Os tipos destes valores têm de concordar com o tipo declarado. Quando o tipo a retornar não é primitivo (i.e., é um tuplo), os valores são copiados para a zona de memória reservada pelo chamador e passada por ponteiro à função como o seu primeiro argumento (ver acima).
 
 
 
É um erro especificar um valor de retorno para procedimentos.
 
 
 
Qualquer sub-bloco (usado, por exemplo, numa instrução condicional ou de iteração) pode definir variáveis.
 
 
 
== Função principal e execução de programas ==
 
 
 
Um programa inicia-se com a invocação da função '''og''' (sem argumentos). Os argumentos com que o programa foi chamado podem ser obtidos através das seguintes funções:
 
* '''int argc()''' (devolve o número de argumentos);
 
* '''string argv(int n)''' (devolve o n-ésimo argumento como uma cadeia de caracteres) ('''n>0'''); e
 
* '''string envp(int n)''' (devolve a n-ésima variável de ambiente como uma cadeia de caracteres) ('''n>0''').
 
 
 
O valor de retorno da função principal é devolvido ao ambiente que invocou o programa. Este valor de retorno segue as seguintes regras (sistema operativo):
 
* 0 (zero): execução sem erros;
 
* 1 (um): argumentos inválidos (em número ou valor);
 
* 2 (dois): erro de execução.
 
Os valores superiores a 128 indicam que o programa terminou com um sinal. Em geral, para correcto funcionamento, os programas devem retornar 0 (zero) se a execução foi bem sucedida e um valor diferente de 0 (zero) em caso de erro.
 
 
 
A [[Compiladores/Projecto de Compiladores/Material de Apoio ao Desenvolvimento|biblioteca de run-time]] (RTS) contém informação sobre outras funções de suporte disponíveis, incluindo chamadas ao sistema (ver também o [[Manual da RTS|manual da RTS]]).
 
 
 
= Instruções =
 
 
 
Excepto quando indicado, as instruções são executadas em sequência.
 
 
 
== Blocos ==
 
 
 
Cada bloco tem uma zona de declarações de variáveis locais (facultativa), seguida por uma zona com instruções (possivelmente vazia). Não é possível declarar ou definir funções dentro de blocos.
 
 
 
A visibilidade das variáveis é limitada ao bloco em que foram declaradas. As entidades declaradas podem ser directamente utilizadas em sub-blocos ou passadas como argumentos para funções chamadas dentro do bloco. Caso os identificadores usados para definir as variáveis locais já estejam a ser utilizados para definir outras entidades ao alcance do bloco, o novo identificador passa a referir uma nova entidade definida no bloco até que ele termine (a entidade previamente definida continua a existir, mas não pode ser directamente referida pelo seu nome). Esta regra é também válida relativamente a argumentos de funções (ver [[#Corpo|corpo das funções]]).
 
 
 
== Instrução condicional ==
 
 
 
Esta instrução tem comportamento idêntico ao da instrução '''if-else''' em C.
 
 
 
== Instrução de iteração ==
 
 
 
Esta instrução tem comportamento idêntico ao da instrução '''for''' em C. Na zona de declaração de variáveis, apenas pode ser usada uma declaração '''auto''', devendo ser, nesse caso, a única.
 
 
 
== Instrução de terminação ==
 
 
 
A instrução '''break''' termina o ciclo mais interior em que a instrução se encontrar, tal como a instrução '''break''' em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.
 
 
 
== Instrução de continuação ==
 
 
 
A instrução '''continue''' reinicia o ciclo mais interior em que a instrução se encontrar, tal como a instrução '''continue''' em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.
 
 
 
== Instrução de retorno ==
 
 
 
A instrução '''return''', se existir, é a última instrução do seu bloco. Ver comportamento na [[#Corpo|descrição do corpo de uma função]].
 
 
 
== Expressões como instruções ==
 
 
 
As expressões utilizadas como instruções são avaliadas, mesmo que não produzam efeitos secundários. A notação é como indicada na gramática (expressão seguida de ''';''').
 
 
 
== Instruções de impressão ==
 
 
 
As palavras chave '''write''' e '''writeln''' podem ser utilizadas para apresentar valores na saída do programa. A primeira apresenta a expressão sem mudar de linha; a segunda apresenta a expressão mudando de linha. Quando existe mais de uma expressão, as várias expressões são apresentadas sem separação. Valores numéricos (inteiros ou reais) são impressos em decimal. As cadeias de caracteres são impressas na codificação nativa. Ponteiros não podem ser impressos.
 
 
 
= Expressões =
 
 
 
Uma expressão é uma representação algébrica de uma quantidade: todas as expressões têm um tipo e devolvem um valor.
 
 
 
Existem [[#Expressões primitivas|expressões primitivas]] e expressões que resultam da  [[#Expressões resultantes de avaliação de operadores|avaliação de operadores]].
 
 
 
A tabela seguinte apresenta as precedências relativas dos operadores: é a mesma para operadores na mesma linha, sendo as linhas seguintes de menor prioridade que as anteriores. A maioria dos operadores segue a semântica da linguagem C (excepto onde explicitamente indicado). Tal como em C, os valores lógicos são 0 (zero) (valor falso), e diferente de zero (valor verdadeiro).
 
 
 
{|
 
| '''Tipo de Expressão'''
 
| '''Operadores'''
 
| '''Associatividade'''
 
| '''Operandos'''
 
| '''Semântica'''
 
|-
 
| primária
 
| '''( ) [ ]'''
 
| não associativos
 
| -
 
| [[#Parênteses curvos|parênteses curvos]], [[#Indexação|indexação]], [[#Reserva de memória|reserva de memória]]
 
|-
 
| unária
 
| '''+ - ?'''
 
| não associativos
 
| -
 
| [[#Identidade e simétrico|identidade e simétrico]], [[#Expressão de indicação de posição|indicação de posição]]
 
|-
 
! style="vertical-align: top; font-weight: normal;" | multiplicativa
 
! style="vertical-align: top; font-weight: normal;" | '''* / %'''
 
! style="vertical-align: top; font-weight: normal;" | da esquerda para a direita
 
! style="vertical-align: top; font-weight: normal;" | inteiros, reais
 
! style="vertical-align: top; font-weight: normal;" | C (% é apenas para inteiros)
 
|-
 
! style="vertical-align: top; font-weight: normal;" | aditiva
 
! style="vertical-align: top; font-weight: normal;" | '''+ -'''
 
! style="vertical-align: top; font-weight: normal;" | da esquerda para a direita
 
! style="vertical-align: top; font-weight: normal;" | inteiros, reais, ponteiros
 
! style="vertical-align: top; font-weight: normal;" | C: se envolverem ponteiros, calculam: (i) deslocamentos, i.e., um dos operandos deve ser do tipo ponteiro e o outro do tipo inteiro; (ii) diferenças de ponteiros, i.e., apenas quando se aplica o operador '''-''' a dois ponteiros do mesmo tipo (o resultado é o número de objectos do tipo apontado entre eles). Se a memória não for contígua, o resultado é indefinido.
 
|-
 
! style="vertical-align: top; font-weight: normal;" | comparativa
 
! style="vertical-align: top; font-weight: normal;" | '''< > <= >='''
 
! style="vertical-align: top; font-weight: normal;" | da esquerda para a direita
 
! style="vertical-align: top; font-weight: normal;" | inteiros, reais
 
! style="vertical-align: top; font-weight: normal;" | C
 
|-
 
! style="vertical-align: top; font-weight: normal;" | igualdade
 
! style="vertical-align: top; font-weight: normal;" | '''== !='''
 
! style="vertical-align: top; font-weight: normal;" | da esquerda para a direita
 
! style="vertical-align: top; font-weight: normal;" | inteiros, reais, ponteiros
 
! style="vertical-align: top; font-weight: normal;" | C
 
|-
 
! style="vertical-align: top; font-weight: normal;" | "não" lógico
 
! style="vertical-align: top; font-weight: normal;" | '''~'''
 
! style="vertical-align: top; font-weight: normal;" | não associativo
 
! style="vertical-align: top; font-weight: normal;" | inteiros
 
! style="vertical-align: top; font-weight: normal;" | C
 
|-
 
! style="vertical-align: top; font-weight: normal;" | "e" lógico
 
! style="vertical-align: top; font-weight: normal;" | '''&&'''
 
! style="vertical-align: top; font-weight: normal;" | da esquerda para a direita
 
! style="vertical-align: top; font-weight: normal;" | inteiros
 
! style="vertical-align: top; font-weight: normal;" | C: o 2º argumento só é avaliado se o 1º não for falso.
 
|-
 
! style="vertical-align: top; font-weight: normal;" | "ou" lógico
 
! style="vertical-align: top; font-weight: normal;" | '''<nowiki>||</nowiki>'''
 
! style="vertical-align: top; font-weight: normal;" | da esquerda para a direita
 
! style="vertical-align: top; font-weight: normal;" | inteiros
 
! style="vertical-align: top; font-weight: normal;" | C: o 2º argumento só é avaliado se o 1º não for verdadeiro.
 
|-
 
! style="vertical-align: top; font-weight: normal;" | atribuição
 
! style="vertical-align: top; font-weight: normal;" | '''='''
 
! style="vertical-align: top; font-weight: normal;" | da direita para a esquerda
 
! style="vertical-align: top; font-weight: normal;" | todos os tipos (excepto tuplos)
 
! style="vertical-align: top; font-weight: normal;" | O valor da expressão do lado direito do operador é guardado na posição indicada pelo ''left-value'' (operando esquerdo do operador). Podem ser atribuídos valores inteiros a ''left-values'' reais (conversão automática). Nos outros casos, ambos os tipos têm de concordar.
 
|}
 
 
 
== Expressões primitivas ==
 
 
 
As [[#Literais|expressões literais]] e a [[#Invocação|invocação de funções]] foram definidas acima.
 
 
 
=== Identificadores ===
 
 
 
Um identificador é uma expressão se tiver sido declarado. Um identificador pode denotar uma variável.
 
 
 
Um identificador é o caso mais simples de um ''[[#Left-values|left-value]]'', ou seja, uma entidade que pode ser utilizada no lado esquerdo (''left'') de uma atribuição.
 
 
 
=== Leitura ===
 
 
 
A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão indicada pela palavra reservada '''input''', que devolve o valor lido, de acordo com o tipo esperado (inteiro ou real). Caso se use como argumento dos operadores de impressão ou noutras situações que permitam várias tipos ('''write''' ou '''writeln'''), deve ser lido um inteiro.
 
 
 
Exemplos:  '''a = input''' (leitura para '''a'''), '''f(input)''' (leitura para argumento de função), '''write input''' (leitura e impressão).
 
 
 
=== Parênteses curvos ===
 
 
 
Uma expressão entre parênteses curvos tem o valor da expressão sem os parênteses e permite alterar a prioridade dos operadores. Uma expressão entre parênteses não pode ser utilizada como ''left-value'' (ver também a [[#Indexação|expressão de indexação]]).
 
 
 
== Expressões resultantes de avaliação de operadores ==
 
 
 
=== Indexação de ponteiros ===
 
 
 
A indexação de ponteiros devolve o valor de uma posição de memória indicada por um ponteiro. Consiste de uma expressão ponteiro seguida do índice entre parênteses rectos. O resultado de uma indexação de ponteiros é um ''[[#Left-values|left-value]]''.
 
 
 
Exemplo (acesso à posição 0 da zona de memória indicada por '''p'''): '''p[0]'''
 
 
 
=== Indexação de tuplos ===
 
 
 
A indexação de tuplos devolve o valor de uma posição de um tuplo indicada por um número de ordem (início em 1). Consiste de um tuplo seguido de um literal inteiro que indica a posição. O resultado de uma indexação de tuplos é um ''[[#Left-values|left-value]]''.
 
 
 
Exemplo (acesso à segunda posição do tuplo '''a'''): '''a@2'''
 
 
 
=== Identidade e simétrico ===
 
 
 
Os operadores identidade ('''+''') e simétrico ('''-''') aplicam-se a inteiros e reais. Têm o mesmo significado que em C.
 
 
 
=== Reserva de memória ===
 
 
 
A expressão reserva de memória devolve o ponteiro que aponta para a zona de memória, na pilha da função actual, contendo espaço suficiente para o número de objectos indicados pelo seu argumento inteiro.
 
 
 
Exemplo (reserva vector com 5 reais, apontados por '''p'''): '''ptr<real>p = [5]'''
 
 
 
=== Expressão de indicação de posição ===
 
 
 
O operador sufixo '''?''' aplica-se a ''left-values'', retornando o endereço (com o tipo ponteiro) correspondente.
 
 
 
Exemplo (indica o endereço de '''a'''): '''a?'''
 
 
 
=== Expressão de dimensão ===
 
 
 
O operador '''sizeof''' aplica-se a expressões, retornando a dimensão correspondente em bytes. Aplicado a um tuplo, retorna a soma das dimensões dos seus componentes.
 
 
 
Exemplos: '''sizeof(a)''' (dimensão de '''a'''); '''sizeof(1, 2)''' (8 bytes).
 
 
 
= Exemplos =
 
 
 
Os exemplos não são exaustivos e não ilustram todos os aspectos da linguagem. Podem obter-se outros na página da disciplina.
 
 
 
== Programa com vários módulos ==
 
 
 
Definição da função ''factorial'' num ficheiro ('''factorial.og'''):
 
 
 
public int factorial(int n) {
 
  if n > 1 then return n * factorial(n-1); else return 1;
 
}
 
 
 
Exemplo da utilização da função ''factorial'' num outro ficheiro ('''main.og'''):
 
 
 
// external builtin functions
 
require int argc()
 
require string argv(int n)
 
require int atoi(string s)
 
 
// external user functions
 
require int factorial(int n)
 
 
// the main function
 
public int og() {
 
  int f = 1;
 
  writeln "Teste para a função factorial";
 
  if argc() == 2 then f = atoi(argv(1));
 
  writeln f, "! = ", factorial(f);
 
  return 0;
 
}
 
 
 
Como compilar:
 
 
 
fir --target asm factorial.og
 
fir --target asm main.og
 
yasm -felf32 factorial.asm
 
yasm -felf32 main.asm
 
ld -melf_i386 -o main factorial.o main.o -lrts
 
 
 
== Outros testes ==
 
 
 
Estão disponíveis outros [[Compiladores/Projecto de Compiladores/Testes Automáticos 2020-2021|pacotes de testes]].
 
 
 
= Omissões e Erros =
 
 
 
Casos omissos e erros serão corrigidos em futuras versões do manual de referência.
 
<!--
 
[[category:Projecto de Compiladores]]
 
[[category:Compiladores]]
 
[[category:Ensino]]
 
-->
 

Latest revision as of 18:39, 25 February 2021