(→Função principal e execução de programas) |
(→Intruções) |
||
(52 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{PRJCompiladoreAvisos|co15@l2f.inesc-id.pt|2015/03/25 12:00|2015/04/14 12:00|2015/05/20 12:00|2015/05/20-2015/05/27}} | {{PRJCompiladoreAvisos|co15@l2f.inesc-id.pt|2015/03/25 12:00|2015/04/14 12:00|2015/05/20 12:00|2015/05/20-2015/05/27}} | ||
+ | {{CDKRTS|CDK10|libcdk10-201502141815.tar.bz2|RTS3|librts3-201502141815.tar.bz2}} | ||
{{TOCright}} | {{TOCright}} | ||
− | + | <!-- '''<font color="red">ENUNCIADO EM PREPARAÇÃO</font>''' --> | |
− | '''<font color="red">ENUNCIADO EM PREPARAÇÃO</font>''' | ||
A linguagem '''pwn''' é uma linguagem imperativa e é apresentada de forma intuitiva neste manual. São apresentadas características básicas 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]]. | A linguagem '''pwn''' é uma linguagem imperativa e é apresentada de forma intuitiva neste manual. São apresentadas características básicas 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]]. | ||
Line 10: | Line 10: | ||
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados, todos compatíveis com a linguagem C, e com alinhamento em memória sempre a 32 bits: | A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados, todos compatíveis com a linguagem C, e com alinhamento em memória sempre a 32 bits: | ||
− | * Tipos numéricos: os '''inteiros''', em complemento para dois, ocupam 4 bytes; os '''reais''', em vírgula flutuante, ocupam 8 bytes. | + | * Tipos numéricos: os '''inteiros''', em complemento para dois, ocupam 4 bytes; os '''reais''', em vírgula flutuante, ocupam 8 bytes (IEEE 754). |
* As '''cadeias de caracteres''' são vectores de caracteres terminados por 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. | * As '''cadeias de caracteres''' são vectores de caracteres terminados por 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 números reais e ocupam 4 bytes. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado. | * Os '''ponteiros''' representam endereços de números reais e ocupam 4 bytes. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado. | ||
Line 48: | Line 48: | ||
== Palavras chave == | == Palavras chave == | ||
− | Estas palavras são reservadas e não constituem identificadores: | + | Estas palavras são reservadas e não constituem identificadores: '''local import if else repeat next stop return noob''' |
+ | |||
+ | O identificador '''pwn''', embora não reservado, corresponde à [[#Função principal e execução de programas|função principal]]. | ||
== Tipos == | == Tipos == | ||
− | Os seguintes elementos lexicais designam tipos em declarações (ver [[#Gramática|gramática]]): | + | Os seguintes elementos lexicais designam tipos em declarações (ver também a [[#Gramática|gramática]]): '''#''' (inteiro), '''%''' (real), '''$''' (cadeia de caracteres) e '''*''' (ponteiro). |
== Operadores de expressões == | == Operadores de expressões == | ||
Line 60: | Line 62: | ||
== Delimitadores e terminadores == | == Delimitadores e terminadores == | ||
− | Os seguintes elementos lexicais são | + | 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) == | == Identificadores (nomes) == | ||
Line 99: | Line 101: | ||
=== Ponteiros === | === Ponteiros === | ||
− | O único literal admissível para ponteiros é ''' | + | O único literal admissível para ponteiros é '''noob''' (no-object), i.e., indica o ponteiro nulo. |
= Gramática = | = 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, que elementos alternativos são separados por uma barra vertical, que elementos opcionais estão entre parênteses rectos, que os elementos que se repetem zero ou mais vezes estão entre <amsmath>\langle</amsmath> e <amsmath>\rangle</amsmath>. Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses). | 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, que elementos alternativos são separados por uma barra vertical, que elementos opcionais estão entre parênteses rectos, que os elementos que se repetem zero ou mais vezes estão entre <amsmath>\langle</amsmath> e <amsmath>\rangle</amsmath>. 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;" | <amsmath>\rightarrow</amsmath> | ||
+ | | <amsmath>\langle</amsmath> ''declaração'' <amsmath>\rangle</amsmath> | ||
+ | |- | ||
+ | ! style="width: 150px; font-weight: normal;" | ''declaração'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | ''variável'' ''';''' <amsmath>|</amsmath> ''função'' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''variável'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | [ '''local''' <amsmath>|</amsmath> '''import''' ] ''tipo'' ''identificador'' [ '''=''' ''expressão'' ] | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''função'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | [ '''local''' <amsmath>|</amsmath> '''import''' ] ( ''tipo'' <amsmath>|</amsmath> '''!''' ) ''identificador'' '''(''' [ ''variáveis'' ] ''')''' [ '''=''' ''literal'' ] [ ''corpo'' ] | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''variáveis'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | ''variável'' <amsmath>\langle</amsmath> ''',''' ''variável'' <amsmath>\rangle</amsmath> | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''tipo'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | '''#''' <amsmath>|</amsmath> '''%''' <amsmath>|</amsmath> '''$''' <amsmath>|</amsmath> '''*''' <amsmath>|</amsmath> '''<''' ''tipo'' '''>''' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''corpo'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | ''bloco'' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''bloco'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | '''{''' <amsmath>\langle</amsmath> ''declaração'' <amsmath>\rangle</amsmath> <amsmath>\langle</amsmath> ''instrução'' <amsmath>\rangle</amsmath> '''}''' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''instrução'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | ''expressão'' ''';''' <amsmath>|</amsmath> ''expressão'' '''!''' <amsmath>|</amsmath> ''expressão'' '''!!''' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | '''stop''' [ ''literal-inteiro'' ] ''';''' <amsmath>|</amsmath> '''next''' [ ''literal-inteiro'' ] ''';''' <amsmath>|</amsmath> '''return''' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | ''instrução-condicional'' <amsmath>|</amsmath> ''instrução-de-iteração'' <amsmath>|</amsmath> ''bloco'' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''instrução-condicional'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | '''if''' '''(''' ''expressão'' ''')''' ''instrução'' [ '''else''' ''instrução'' ] | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''instrução-de-iteração'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | '''repeat''' '''(''' [ ''expressões'' ] ''';''' [ ''expressões'' ] ''';''' [ ''expressões'' ] ''')''' ''instrução'' | ||
+ | |- | ||
+ | ! style="width: 50px; font-weight: normal;" | ''expressões'' | ||
+ | ! style="width: 50px; font-weight: normal;" |<amsmath>\rightarrow</amsmath> | ||
+ | | ''expressão'' <amsmath>\langle</amsmath> ''',''' ''expressão'' <amsmath>\rangle</amsmath> | ||
+ | |} | ||
== Tipos, identificadores, literais e definição de expressões == | == 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'' e ''literal-inteiro'' (ver [[#Literais|literais]]); ''expressão'' (ver [[#Expressões|expressões]]). | ||
== Left-values == | == Left-values == | ||
Line 124: | Line 186: | ||
Exemplos: | Exemplos: | ||
− | * Inteiro: | + | * Inteiro: '''#i''' |
− | * Real: | + | * Real: '''%r''' |
− | * Ponteiro: | + | * Ponteiro: '''*p''' |
− | * Cadeia de caracteres: | + | * Cadeia de caracteres: '''$s''' |
== Constantes == | == Constantes == | ||
− | A definição de um identificador constante impede que possa ser utilizado em operações que modifiquem o seu valor. Caso um identificador designe uma constante inteira não pública (ver [[#Símbolos globais|símbolos globais]]) o seu valor deverá ser directamente substituído no código | + | A definição de um identificador constante impede que possa ser utilizado em operações que modifiquem o seu valor. Caso um identificador designe uma constante inteira não pública (ver [[#Símbolos globais|símbolos globais]]) o seu valor deverá ser directamente substituído no código. |
Exemplos: | Exemplos: | ||
− | * Inteiro constante: | + | * Inteiro constante: '''<#>i = 2''' |
− | * Ponteiro constante: | + | * Real constante: '''<%>e = 2.71828182845904523536 /*''' [http://apod.nasa.gov/htmltest/gifcity/e.2mil] '''*/''' |
+ | * Ponteiro constante: '''<*>p = e?''' | ||
== Símbolos globais == | == Símbolos globais == | ||
− | Por omissão, os símbolos são públicos, podendo | + | Por omissão, os símbolos são públicos, podendo ser importados por outros módulos. |
A palavra '''local''' permite declarar um identificador como privado a um módulo, tornando-o inacessível a partir de outros módulos. | A palavra '''local''' permite declarar um identificador como privado a um módulo, tornando-o inacessível a partir de outros módulos. | ||
− | |||
A palavra '''import''' (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 '''import'''. | A palavra '''import''' (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 '''import'''. | ||
− | + | ||
+ | Exemplos: | ||
+ | * Declarar variável privada ao módulo: '''local <%>pi = 22/7 /*''' [http://en.wikipedia.org/wiki/Proof_that_22/7_exceeds_%CF%80] '''*/''' | ||
+ | * Usar definição externa: '''import <%>pi''' | ||
== Inicialização == | == Inicialização == | ||
Line 154: | Line 219: | ||
Exemplos: | Exemplos: | ||
− | * Inteiro (literal): | + | * Inteiro (literal): '''<#>i = 3''' |
− | * | + | * Inteiro (expressão): '''# i = j+1''' |
− | * | + | * Real (literal): '''% r = 3.2''' |
− | * Real (expressão): | + | * Real (expressão): '''<%>r = i - 2.5 + f(3)''' |
− | * Cadeia de caracteres (literal): | + | * Cadeia de caracteres (literal): '''<$>s = "olá"''' |
− | * | + | * Cadeia de caracteres (literais): '''$s = "olá" "mãe"''' |
− | * | + | * Ponteiro (literal): '''*p = noob''' |
− | * Ponteiro (expressão): | + | * Ponteiro (expressão): '''<*>p = q + 1''' |
A declaração de constantes sem valor inicial só é possível se corresponder a identificadores pertencentes a outros módulos (ver [[#Símbolos globais|símbolos globais]]). | A declaração de constantes sem valor inicial só é possível se corresponder a identificadores pertencentes a outros módulos (ver [[#Símbolos globais|símbolos globais]]). | ||
Line 203: | Line 268: | ||
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 devolver 0 (zero) se a execução foi bem sucedida e um valor diferente de 0 (zero) em caso de erro. | 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 devolver 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 | + | 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. | Excepto quando indicado, as instruções são executadas em sequência. | ||
Line 221: | Line 286: | ||
== Instrução de iteração == | == Instrução de iteração == | ||
− | + | A instrução '''repeat''' tem comportamento idêntico ao da instrução '''for''' em C. | |
== Instrução de terminação == | == Instrução de terminação == | ||
− | + | A instrução '''stop''' termina o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se '''n=1'''), 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 == | == Instrução de continuação == | ||
− | + | A instrução '''next''' reinicia o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se '''n=1'''), 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 == | == Instrução de retorno == | ||
Line 240: | Line 305: | ||
= Expressões = | = 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;" | '''|''' | ||
+ | ! 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 == | == Expressões primitivas == | ||
+ | |||
+ | As [[#Literais|expressões literais]] e a [[#Invocação|invocação de funções]] foram definidas acima. | ||
=== Identificadores === | === 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 === | === Leitura === | ||
+ | |||
+ | A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão '''@''', 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 = @''' (leitura para '''a'''), '''f(@)''' (leitura para argumento de função), '''@!!''' (leitura e impressão). | ||
=== Parênteses curvos === | === 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 == | == Expressões resultantes de avaliação de operadores == | ||
=== Indexação === | === Indexação === | ||
+ | |||
+ | A indexação 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. Se a expressão ponteiro for um ''[[#Left-values|left-value]]'', então a expressão indexação poderá também ser um '''left-value'' (excepto nas condições proibidas pelo tipo). | ||
+ | |||
+ | Exemplo (acesso à posição indicada por '''p'''): '''p[0]''' | ||
=== Identidade e simétrico === | === 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 === | === 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 reais indicados pelo seu argumento inteiro. | ||
+ | |||
+ | Exemplo (reserva vector com 5 reais, apontados por '''p'''): '''*p=[5]''' | ||
=== Expressão de indicação de posição === | === Expressão de indicação de posição === | ||
+ | |||
+ | O operador sufixo '''?''' aplica-se a ''left-values'' reais, retornando o endereço correspondente. | ||
+ | |||
+ | Exemplo (indica o endereço de '''a'''): '''a?''' | ||
= Exemplos = | = Exemplos = | ||
Line 263: | Line 428: | ||
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. | 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 (ficheiro '''factorial.pwn'''): | ||
− | + | #factorial(#n) = 1 { | |
+ | if (n > 1) factorial = n * factorial(n-1); else factorial = 1; | ||
+ | } | ||
− | + | Exemplo da utilização da função ''factorial'' num outro ficheiro (ficheiro '''main.pwn'''): | |
− | == | + | // external builtin functions |
+ | import #argc() | ||
+ | import $argv(#n) | ||
+ | import #atoi($s) | ||
+ | |||
+ | // external user functions | ||
+ | import #factorial(#n) | ||
+ | |||
+ | // the main function | ||
+ | #pwn() { | ||
+ | #f = 1; | ||
+ | "Teste para a função factorial"!! | ||
+ | if (argc() == 2) f = atoi(argv(1)); | ||
+ | f! "! = "! factorial(f)!! | ||
+ | } | ||
− | + | == Outros testes == | |
− | + | Estão disponíveis outros [[Compiladores/Projecto_de_Compiladores/Projecto_2014-2015/Testes_Automáticos|pacotes de testes]]. | |
= Omissões e Erros = | = Omissões e Erros = |
AVISOS - Avaliação em Época Normal |
---|
Esclarecimento de dúvidas:
|
Requisitos para desenvolvimento, material de apoio e actualizações do enunciado (ver informação completa em Projecto de Compiladores):
|
Processo de avaliação (ver informação completa em Avaliação do Projecto):
|
Material de Uso Obrigatório |
---|
As bibliotecas CDK e RTS de apoio ao desenvolvimento do projecto são de uso obrigatório: |
|
A máquina virtual, fornecida para desenvolvimento do projecto, já contém todo o material de apoio. |
Uso Obrigatório: Repositório GIT |
Apenas se consideram para avaliação os projectos existentes no repositório GIT oficial. Apenas se considera para avaliação o ramo main.
Trabalhos não presentes no repositório no final do prazo têm classificação 0 (zero) (não são aceites outras formas de entrega). Não são admitidas justificações para atrasos em sincronizações do repositório. A indisponibilidade temporária do repositório, desde que inferior a 24 horas, não justifica atrasos na submissão de um trabalho. |
A linguagem pwn é uma linguagem imperativa e é apresentada de forma intuitiva neste manual. São apresentadas características básicas da linguagem (tipos de dados, manipulação de nomes); convenções lexicais; estrutura/sintaxe; especificação das funções; semântica das instruções; semântica das expressões; e, finalmente, alguns exemplos.
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados, todos compatíveis com a linguagem C, e com alinhamento em memória sempre a 32 bits:
Os tipos suportados por cada operador e a operação a realizar são indicados na definição das expressões.
Os nomes (identificadores) correspondem a constantes, variáveis e funções. Nos pontos que se seguem, usa-se o termo entidade para as designar indiscriminadamente, usando-se explicitando-se quando a descrição for válida apenas para um subconjunto.
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. É possível utilizar símbolos globais nos contextos das funções, mas não é possível defini-los (ver símbolos globais).
As entidades globais (declaradas fora de qualquer função), existem durante toda a execução do programa. As contantes e 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.
Para cada grupo de elementos lexicais (tokens), considera-se a maior sequência de caracteres constituindo um elemento válido.
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).
Existem dois tipos de comentários, que também funcionam como elementos separadores:
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).
Estas palavras são reservadas e não constituem identificadores: local import if else repeat next stop return noob
O identificador pwn, embora não reservado, corresponde à função principal.
Os seguintes elementos lexicais designam tipos em declarações (ver também a gramática): # (inteiro), % (real), $ (cadeia de caracteres) e * (ponteiro).
São considerados operadores os elementos lexicais apresentados na definição das expressões.
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).
São iniciados por uma letra ou por _ (sublinhado), 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.
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).
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 menos unário (-) 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).
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.
Se não for possível representar o literal inteiro na máquina, devido a um overflow, deverá ser gerado um erro lexical.
Os literais reais são expressos em notação científica (tal como em C). Exemplo: 12.34e-24 = 12.34 x 10-24.
Um literal sem . (ponto decimal) nem parte exponencial é do tipo inteiro.
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. Exemplo: "ab""cd" é o mesmo que "abcd".
O único literal admissível para ponteiros é noob (no-object), i.e., indica o ponteiro nulo.
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, que elementos alternativos são separados por uma barra vertical, que elementos opcionais estão entre parênteses rectos, que os elementos que se repetem zero ou mais vezes estão entre e . Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses).
ficheiro | declaração | |
---|---|---|
declaração | variável ; função | |
variável | [ local import ] tipo identificador [ = expressão ] | |
função | [ local import ] ( tipo ! ) identificador ( [ variáveis ] ) [ = literal ] [ corpo ] | |
variáveis | variável , variável | |
tipo | # % $ * < tipo > | |
corpo | bloco | |
bloco | { declaração instrução } | |
instrução | expressão ; expressão ! expressão !! | |
stop [ literal-inteiro ] ; next [ literal-inteiro ] ; return | ||
instrução-condicional instrução-de-iteração bloco | ||
instrução-condicional | if ( expressão ) instrução [ else instrução ] | |
instrução-de-iteração | repeat ( [ expressões ] ; [ expressões ] ; [ expressões ] ) instrução | |
expressões | expressão , expressão |
Algumas definições foram omitidas da gramática: tipos de dados, identificador (ver identificadores), literal e literal-inteiro (ver literais); expressão (ver expressões).
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 semântica das expressões.
Um ficheiro é designado por principal se contiver a função principal (a que inicia o programa).
As declarações de variáveis ou constantes incluem os componentes descritos nos pontos seguintes.
Um declaração indica sempre um tipo de dados e um identificador.
Exemplos:
A definição de um identificador constante impede que possa ser utilizado em operações que modifiquem o seu valor. Caso um identificador designe uma constante inteira não pública (ver símbolos globais) o seu valor deverá ser directamente substituído no código.
Exemplos:
Por omissão, os símbolos são públicos, podendo ser importados por outros módulos.
A palavra local permite declarar um identificador como privado a um módulo, tornando-o inacessível a partir de outros módulos.
A palavra import (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 import.
Exemplos:
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 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:
A declaração de constantes sem valor inicial só é possível se corresponder a identificadores pertencentes a outros módulos (ver símbolos globais).
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.
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, usar-se o marcador de tipo especial ! 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 local ou import (ver 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 o qualificador import).
A função só pode ser invocada através de um identificador que refira uma função previamente declarada ou definida.
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.
O corpo de uma função consiste num bloco que contém declarações (opcionais) seguidas de instruções (opcionais). Não é possível aplicar os qualificadores local ou import (ver 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 com o nome da função, deve ser do tipo declarado.
Se existir um valor declarado por omissão para o retorno da função (indicado pela notação = seguindo a assinatura da função), então deve ser utilizado se não for especificado outro. A especificação do valor de retorno por omissão é obrigatoriamente um literal do tipo indicado. É um erro especificar um valor de retorno se a função for declarada como não retornando um valor (tipo indicado como !). Uma função cujo retorno seja inteiro ou ponteiro retorna 0 (zero) por omissão (i.e., se não for especificado o valor de retorno). Em todos os outros casos, o valor de retorno é indeterminado se não for definido explicitamente.
Uma instrução return causa a interrupção da função e o retorno do seu valor actual ao chamador.
Qualquer bloco (usado, por exemplo, numa instrução condicional ou de iteração) pode definir variáveis ou constantes.
Um programa inicia-se com a invocação da função pwn (sem argumentos). Os argumentos com que o programa foi chamado podem ser obtidos através de funções #argc() (devolve o número de argumentos); $argv(#n) (devolve o n-ésimo argumento como uma cadeia de caracteres) (n>0); e $envp(#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 devolver 0 (zero) se a execução foi bem sucedida e um valor diferente de 0 (zero) em caso de erro.
A 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).
Excepto quando indicado, as instruções são executadas em sequência.
Cada bloco tem uma zona de declarações de constantes e variáveis locais (facultativa), seguida por uma zona com instruções.
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 constantes e 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 das funções).
Esta instrução tem comportamento idêntico ao da instrução if-else em C.
A instrução repeat tem comportamento idêntico ao da instrução for em C.
A instrução stop termina o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se n=1), 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.
A instrução next reinicia o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se n=1), 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.
Se existir, é a última instrução do seu bloco. Ver comportamento na descrição do corpo de uma funçã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.
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 e expressões que resultam da 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, indexação, reserva de memória |
unária | + - ? | não associativos | - | identidade e simétrico, indicação de posição |
multiplicativa | * / % | da esquerda para a direita | inteiros, reais | C (% é apenas para inteiros) |
---|---|---|---|---|
aditiva | + - | da esquerda para a direita | inteiros, reais, ponteiros | 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. |
comparativa | < > <= >= | da esquerda para a direita | inteiros, reais | C |
igualdade | == <> | da esquerda para a direita | inteiros, reais, ponteiros | C |
"não" lógico | ~ | não associativo | inteiros | C |
"e" lógico | & | da esquerda para a direita | inteiros | C: o 2º argumento só é avaliado se o 1º não for falso. |
"ou" lógico | | | da esquerda para a direita | inteiros | C: o 2º argumento só é avaliado se o 1º não for verdadeiro. |
atribuição | = | da direita para a esquerda | todos os tipos | 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. |
As expressões literais e a invocação de funções foram definidas acima.
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-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 das funções).
A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão @, 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 = @ (leitura para a), f(@) (leitura para argumento de função), @!! (leitura e impressão).
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 expressão de indexação).
A indexação 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. Se a expressão ponteiro for um left-value, então a expressão indexação poderá também ser um 'left-value (excepto nas condições proibidas pelo tipo).
Exemplo (acesso à posição indicada por p): p[0]
Os operadores identidade (+) e simétrico (-) aplicam-se a inteiros e reais. Têm o mesmo significado que em C.
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 reais indicados pelo seu argumento inteiro.
Exemplo (reserva vector com 5 reais, apontados por p): *p=[5]
O operador sufixo ? aplica-se a left-values reais, retornando o endereço correspondente.
Exemplo (indica o endereço de a): a?
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.
Definição da função factorial num ficheiro (ficheiro factorial.pwn):
#factorial(#n) = 1 { if (n > 1) factorial = n * factorial(n-1); else factorial = 1; }
Exemplo da utilização da função factorial num outro ficheiro (ficheiro main.pwn):
// external builtin functions import #argc() import $argv(#n) import #atoi($s) // external user functions import #factorial(#n) // the main function #pwn() { #f = 1; "Teste para a função factorial"!! if (argc() == 2) f = atoi(argv(1)); f! "! = "! factorial(f)!! }
Estão disponíveis outros pacotes de testes.
Casos omissos e erros serão corrigidos em futuras versões do manual de referência.