|
|
(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]]
| |
− | -->
| |