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

From Wiki**3

< Compiladores‎ | Projecto de Compiladores
(Leitura)
 
(23 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{PRJCompiladoreAvisosEN20192020}}
+
#REDIRECT [[Compiladores/Projecto de Compiladores/Projecto 2019-2020/Manual de Referência da Linguagem Og]]
<!--{{PRJCompiladoreAvisosEE20192020}}-->
 
{{PRJCOMandatory20192020}}
 
{{TOCright}}
 
<font color="red">'''EM PREPARAÇÃO'''</font>
 
 
 
'''Og''' é 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, 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 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
 
  procedure break continue return if elif else for do
 
 
 
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 inicializador), '''ptr''' (ponteiros). Ver [[#Gramática|gramática]].
 
 
 
O tipo especial '''auto''' é utilizador para indicar que o tipo da variável ou do retorno da função deve ser inferido a partir do tipo do seu inicializador. 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 inicializador: pode ser uma sequência de expressões ou outro tupo. Em ambos os casos, o mesmo número de elementos deve ser o mesmo que o dos identificadores declarados.  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 compatível com inteiros (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>...>>'''.
 
<!--
 
O tipo especial '''void''' é utilizado para indicar que uma função não retorna nenhum valor. Não é possível declarar ponteiros utilizando o tipo '''void'''.
 
-->
 
 
 
== 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 '''!!''' (operações de impressão), 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 digitos 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.
 
 
 
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 é '''0''', 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> '''require''' <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> ''expressão'' '''!''' <math>|</math> ''expressão'' '''!!'''
 
|-
 
! 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 palabvra chave '''require''' (opcional para funções) permite declarar num módulo entidades definidas em outros módulos. As entidades não podem ser inicializadas numa declaração externa.
 
 
 
Exemplos:
 
* Declarar variável privada ao módulo: '''real pi = 22/7  /*''' [[wp:Proof that 22/7 exceeds π|Proof that 22/7 exceeds π]] '''*/'''
 
* Declarar variável pública: '''public real pi = 22/7'''
 
* 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.
 
 
 
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.
 
 
 
== 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.
 
 
 
O valor devolvido por uma função, através de atribuição ao ''left-value'' especial '''@''', deve ser do tipo declarado.
 
 
 
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.
 
 
 
É 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 (excepto para as que são declaradas na secção inicial). 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é ao 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 e operações de impressão ==
 
 
 
As expressões utilizadas como instruções são avaliadas, mesmo que não produzam efeitos secundários, e, eventualmente, o seu valor impresso (quando seguidas de '''!''' ou '''!!''' -- impressão sem/com mudança de linha). 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
 
! 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 ou uma constante.
 
 
 
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. O valor de retorno de uma função é definido por um ''left-value'' especial (ver também definições relativas ao [[#Corpo|corpo das funções]]).
 
 
 
=== 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 '''!!'''), deve ser lido um inteiro.
 
 
 
Exemplos:  '''a = input''' (leitura para '''a'''), '''f(input)''' (leitura para argumento de função), '''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 da indicação da 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 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'''):
 
 
 
#factorial!(#n) {
 
  [n > 1] ? @ = n * @(n-1); : @ = 1;
 
}
 
 
 
Exemplo da utilização da função ''factorial'' num outro ficheiro ('''main.og'''):
 
 
 
// external builtin functions
 
#argc?()
 
$argv?(#n)
 
#atoi?($s)
 
 
// external user functions
 
#factorial?(#n)
 
 
// the main function
 
#m19!() = 0 {
 
  #f = 1;
 
  "Teste para a função factorial"!!
 
  [argc() == 2] # f = atoi(argv(1));
 
  f! "! = "! factorial(f)!!
 
}
 
 
 
Como compilar:
 
 
 
og --target asm factorial.og
 
og --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 2019-2020|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 16:33, 7 February 2020