<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://robots.hlt.inesc-id.pt/w/pt/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Root</id>
	<title>Wiki**3 - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://robots.hlt.inesc-id.pt/w/pt/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Root"/>
	<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php/Special:Contributions/Root"/>
	<updated>2026-05-23T16:21:46Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.3</generator>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026/Pauta_do_Projecto:_Entrega_%22zero%22&amp;diff=17791</id>
		<title>Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega &quot;zero&quot;</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026/Pauta_do_Projecto:_Entrega_%22zero%22&amp;diff=17791"/>
		<updated>2026-05-22T16:07:07Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
== Pauta ==&lt;br /&gt;
Aqui: https://bit.ly/co26-pautas (ver Fénix)&lt;br /&gt;
&lt;br /&gt;
== Prazo de Revisão ==&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;PAUTA FECHADA&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;PAUTA EM ACTUALIZAÇÃO&amp;lt;/font&amp;gt;&#039;&#039;&#039;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Os resultados da entrega inicial podem ser revistos, nos horários de dúvidas, até à data da entrega intermédia.&lt;br /&gt;
&lt;br /&gt;
== Critérios de Avaliação ==&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;A entrega inicial é obrigatória.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;LER COM ATENÇÃO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A avaliação é realizada sobre a versão existente no repositório no final do prazo para a entrega inicial. Projectos que não apresentem alterações relativamente ao conteúdo inicial do repositório não serão considerados.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;Considerando que é um passo crucial na concepção do projecto, a não realização desta entrega conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente exclusão da avaliação da disciplina no ano lectivo actual.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ver também: [[Compiladores/Projecto de Compiladores/Avaliação do Projecto (Época Normal)]].&lt;br /&gt;
&lt;br /&gt;
Advertem-se os alunos sobre a consulta de colegas de anos anteriores. Estas consultas podem ser positivas, mas comportam algum risco, pois o processo e critérios de avaliação podem ter mudado. Além disso, a proficiência do colega pode majorar negativamente o resultado da avaliação em curso. Não são admitidas quaisquer justificações com base na história da disciplina.&lt;br /&gt;
&lt;br /&gt;
Estas condições são aplicáveis à data da entrega inicial.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;Em caso de dúvidas suscitadas por qualquer elemento neste texto, no projecto, ou na disciplina em geral, os alunos são fortemente encorajados a consultar o corpo docente.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #BDDD8D;&amp;quot; | &amp;lt;font color=&amp;quot;forestgreen&amp;quot;&amp;gt;&#039;&#039;&#039;VALORAÇÕES&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Existem &#039;&#039;&#039;2 valores&#039;&#039;&#039; (dos 20 disponíveis para o projecto) associados a esta entrega:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;gestão do projecto: 0.5 valores&#039;&#039;&#039;&lt;br /&gt;
** projecto com a estrutura correcta no repositório GIT: 0.25 valores (i.e., código que não apresente a estrutura canónica de um compilador desenvolvido com a CDK é considerado sem a estrutura correcta -- consultar estas páginas sobre o desenvolvimento do projecto com base no repositório GIT)&lt;br /&gt;
** projecto compila e produz compilador &amp;quot;p6&amp;quot; (&amp;quot;p6&amp;quot;, com letras minúsculas: variações correspondem a &amp;quot;não compilação&amp;quot;): 0.25 valores&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Se o projecto compilar&#039;&#039;&#039;, poderão ser atribuídos mais &#039;&#039;&#039;1.5 valores&#039;&#039;&#039; (desenvolvimento do compilador), distribuídos como se segue:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Classes dos nós do compilador (completo): 1.0 valores&#039;&#039;&#039;&lt;br /&gt;
** Reutilização dos nós da CDK (simples ajuste do Simple)&lt;br /&gt;
** Definição ou extensão de elementos existentes (simples ajuste do Simple)&lt;br /&gt;
** Definição de novas declarações/definições (variáveis/funções) (completo)&lt;br /&gt;
** Definição de novas instruções (completo)&lt;br /&gt;
** Definição de novas expressões (completo)&lt;br /&gt;
** Definição de outros elementos (completo)&lt;br /&gt;
** Sugere-se (por simplicidade de gestão do código) a separação das várias classes de nós em namespaces coerentes (à la Simple)&lt;br /&gt;
** Não é necessário criar as regras na especificação Bison para criar os nós (se for feito, é conveniente para o progresso do projecto, mas não é avaliado nesta entrega)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Métodos dos &amp;quot;visitors&amp;quot; (completo): 0.5 valores&#039;&#039;&#039;&lt;br /&gt;
** Reutilização de métodos já definidos (simples ajuste do Simple)&lt;br /&gt;
** Definição de todos os métodos do_X (correspondentes ao nó da class X) em todos os visitors (simples extensão do Simple)&lt;br /&gt;
** Métodos novos podem estar vazios, mas devem existir&lt;br /&gt;
** Métodos correspondentes a acções semelhantes às existentes devem ser modelados nos existentes (mesmo que não modificados numa primeira instância)&lt;br /&gt;
** A presença de implementações de semântica no postfix_writer (tabela de símbolos, validação de tipos, etc.) não é penalizada, mas não será avaliada nesta entrega&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa; background: #FFCC99;&amp;quot; | &amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;PENALIZAÇÕES&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Existem penalizações relativas à (deficiente) execução do projecto. &lt;br /&gt;
&lt;br /&gt;
São considerados os seguintes aspectos preliminares:&lt;br /&gt;
&lt;br /&gt;
# A linguagem do projecto contém a linguagem Simple, pelo que não há razão para não utilizar completamente o compilador Simple, eventualmente com pequenas alterações (incluindo a passagem de binário para ternário).&lt;br /&gt;
# A semântica da linguagem do projecto contém a da linguagem Simple, pelo que a implementação de alguns aspectos da linguagem do projecto não requer qualquer reimplementação relativamente ao Simple.&lt;br /&gt;
# O compilador Simple foi fornecido completamente funcional, assim como a versão inicial do compilador do projecto no respositório GIT (igual ao Simple e apenas alterado, para ter um nome apropriado).&lt;br /&gt;
# A criação de novos nós não apresenta quaisquer dificuldades (são classes muito simples).&lt;br /&gt;
# Os métodos (na sua maioria, vazios) dos &amp;quot;visitors&amp;quot; são simples paralelos com as classes dos nós e os que não estão vazios são quase 100% reutilizáveis na nova linguagem.&lt;br /&gt;
# O compilador é obrigatoriamente desenvolvido em C++, fazendo-se uso do material de apoio.&lt;br /&gt;
&lt;br /&gt;
Considerando os aspectos 1. a 6., são aplicadas as seguintes penalizações:&lt;br /&gt;
&lt;br /&gt;
* Destruição de funcionalidade do compilador Simple sem substituição por funcionalidade equivalente do compilador do projecto: &#039;&#039;&#039;2 valores&#039;&#039;&#039;&lt;br /&gt;
* Utilização de funções e estruturas C, quando existem alternativas directas C++ (malloc em lugar de new, por exemplo; strcmp, etc. em lugar da classe std::string; e outras): &#039;&#039;&#039;penalização máxima de 1 valor&#039;&#039;&#039;&lt;br /&gt;
* Não utilização de qualquer material obrigatório ou não satisfação dos critérios mínimos: &#039;&#039;&#039;2 valores e considera-se entrega não realizada (implica exclusão da avaliação)&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Legenda ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- &#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;PAUTA PROVISÓRIA -- EM ACTUALIZAÇÃO&amp;lt;/font&amp;gt;&#039;&#039;&#039; --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;Os alunos são encorajados a compreender/verificar/corrigir os problemas reportados, especialmente nos casos em que exista anotação explícita na pauta.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa; background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Anotações da tabela&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
* dups: cópia de código que já está disponível na CDK (não devem existir estas cópias: devem ser usadas as classes da CDK)&lt;br /&gt;
* pointer: este nó não deve existir&lt;br /&gt;
* loop/while: problemas vários com o nó de iteração&lt;br /&gt;
* lvals: más utilizações de left-values (um left-value é a designação de um endereço de escrita)&lt;br /&gt;
* index: problemas com os nós de indexação (e.g. não são lvalues, faltam expressões)&lt;br /&gt;
* decls: faltam nós correspondentes a declarações ou têm problemas (e.g. confundidas com expressões, problemas com tipos, etc.)&lt;br /&gt;
* func decls: problemas com declarações de funções&lt;br /&gt;
* function/func defs: faltam nós correspondentes a definições de funções ou têm problemas: e.g. faltam tipos, têm relações com lvalues (não devem existir)&lt;br /&gt;
* vars: faltam nós correspondentes a declarações/definições de variáveis ou têm problemas: e.g. faltam tipos, têm relações com lvalues (não devem existir)&lt;br /&gt;
* exprs: faltam expressões (tipicamente, faltam operadores, chamadas a funções)&lt;br /&gt;
* file/public/use/qualifier: nós que não devem existir&lt;br /&gt;
* print/write: problemas com o nó de escrita&lt;br /&gt;
* read/input: o nó de leitura deve ser uma expressão e não uma instrução; ao contário do que acontece no Simple, não tem um left-value associado&lt;br /&gt;
* call: este nó tem de ser uma expressão que tem como atributos um nome de função e uma sequência de argumentos&lt;br /&gt;
* alloc/objects: este nó tem de ser uma expressão&lt;br /&gt;
* address: este nó é uma expressão aplicável a um left-value&lt;br /&gt;
* types: não foram os usados os tipos da CDK (basic_type e subclasses) para representar os tipos de dados da linguagem&lt;br /&gt;
* [outras anotações específicas]: contactar o professor responsável&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores 2025-2026]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026&amp;diff=17790</id>
		<title>Compiladores/Pautas 2025-2026</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026&amp;diff=17790"/>
		<updated>2026-05-22T16:06:53Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Pautas do Projecto (época normal) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Além dos resultados de avaliação, as páginas das pautas contêm também os critérios de avaliação e aprovação.&lt;br /&gt;
* {{PautaAberta}} indica avaliação em curso&lt;br /&gt;
* {{PautaFechada}} indica avaliação terminada (classificações definitivas)&lt;br /&gt;
* {{ProvaPorRealizar}} indica avaliação prevista&lt;br /&gt;
&lt;br /&gt;
== Pautas da Disciplina ==&lt;br /&gt;
&lt;br /&gt;
* [[Compiladores/Pautas 2025-2026/Pauta Global da Disciplina|Pauta Global da Disciplina]] -- próxima avaliação: (ver Fénix)&lt;br /&gt;
* {{PautaAberta}} [[Compiladores/Pautas 2025-2026/Pauta das Aulas Práticas|Pauta das Aulas Práticas]] (época nornal)&lt;br /&gt;
&lt;br /&gt;
== Pautas do Projecto (época normal) ==&lt;br /&gt;
&lt;br /&gt;
* {{PautaFechada}} [[Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega &amp;quot;zero&amp;quot;|Pauta do Projecto: Entrega &amp;quot;zero&amp;quot;]]&lt;br /&gt;
* {{PautaAberta}} [[Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega Intermédia|Pauta do Projecto: Entrega Intermédia]]&lt;br /&gt;
* {{ProvaPorRealizar}} [[Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega Final|Pauta do Projecto: Entrega Final]]&lt;br /&gt;
* [[Compiladores/Pautas 2025-2026/Pauta Global do Projecto|Pauta Global do Projecto]]&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores 2025-2026]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17789</id>
		<title>Compiladores/Projecto de Compiladores/Projecto 2025-2026/Manual de Referência da Linguagem P6</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17789"/>
		<updated>2026-05-21T07:54:45Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Gramática */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20252026}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&amp;lt;!--&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;RASCUNHO&#039;&#039;&#039;&amp;lt;/font&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;ÉPOCA NORMAL&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;P6&#039;&#039;&#039; é 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]].&lt;br /&gt;
&lt;br /&gt;
= Tipos de Dados =&lt;br /&gt;
&lt;br /&gt;
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados básicos, apenas alguns dos quais são compatíveis com a [https://en.wikipedia.org/wiki/C_(programming_language) linguagem C]. O alinhamento em memória binária é sempre a 32 bits. Note-se que alguns dos tipos de dados são ternários e devem ser manipulados com as funções das ALUs disponibilizadas.&lt;br /&gt;
&lt;br /&gt;
* Tipos numéricos: os inteiros são [https://en.wikipedia.org/wiki/Balanced_ternary ternários equilibrados], ocupam 40 trits (empacotados em 64 bits); os reais são ternários e estão representados no formato [https://arxiv.org/abs/2404.18603 Takum] (note-se que a definição neste artigo é para uma representação binária e não é exactamente a que é implementada pelas ALUs ternárias em uso no projecto), ocupam 80 trits (empacotados em 128 bits).&lt;br /&gt;
* As cadeias de caracteres são vectores de caracteres binários terminados por [https://en.wikipedia.org/wiki/ASCII ASCII] NUL (carácter com o valor zero). Variáveis e literais deste tipo só podem ser utilizados em atribuições, impressões, ou como argumentos/retornos de funções. Os caracteres são valores de 8 bits não directamente manipuláveis.&lt;br /&gt;
* Os ponteiros representam endereços de objectos (de qualquer tipo) e ocupam 32 bits. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado. Note-se que não é possível usar inteiros ternários directamente em aritmética de ponteiros (têm de ser convertidos para isso).&lt;br /&gt;
&lt;br /&gt;
Os tipos suportados por cada operador e a operação a realizar são indicados na [[#Expressões|definição das expressões]].&lt;br /&gt;
&lt;br /&gt;
Existem ainda tipos associado a valores funcionais, i.e., tipos que descrevem a interface de funções (ver abaixo). Os valores em memória associados a estes tipos são efectivamente ponteiros, mas para funções e não para dados, podendo ser usados para invocar as funções correspondentes. Estes identificadores não podem ser usados como variáveis (e.g., passados como argumentos de outras funções, etc.).&amp;lt;!--Estes ponteiros não aceitam operações de aritmética de ponteiros ou de indexação (embora ponteiros para estes ponteiros as aceitem).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Manipulação de Nomes =&lt;br /&gt;
&lt;br /&gt;
Os nomes (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 dos casos. Existem ainda nomes para funções externas à linguagem P6. Tanto em P6, como em C, os nomes das funções referem directamente a posição do código dessas funções (à la C; ver &#039;&#039;&#039;extern&#039;&#039;&#039; abaixo).&lt;br /&gt;
&lt;br /&gt;
== Espaço de nomes e visibilidade dos identificadores ==&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
Os identificadores são visíveis desde a declaração até ao fim do alcance: ficheiro (globais) ou bloco (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 um bloco. É possível utilizar símbolos globais nos contextos dos blocos das funções, mas não é possível declará-los (ver [[#Símbolos globais|símbolos globais]]).&lt;br /&gt;
&lt;br /&gt;
== Validade das variáveis ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
= Convenções Lexicais =&lt;br /&gt;
&lt;br /&gt;
Para cada grupo de elementos lexicais (tokens), considera-se a maior sequência de caracteres constituindo um elemento válido. Assim, por exemplo, a designação &#039;&#039;&#039;&amp;gt;=&#039;&#039;&#039; é sempre um único elemento lexical (por oposição à situação ilegal de se terem dois símbolos: &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; seguido de &#039;&#039;&#039;=&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Caracteres brancos ==&lt;br /&gt;
&lt;br /&gt;
São considerados separadores e não representam nenhum elemento lexical: &#039;&#039;&#039;mudança de linha&#039;&#039;&#039; ASCII LF (&#039;&#039;&#039;0x0A&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039;), &#039;&#039;&#039;recuo do carreto&#039;&#039;&#039; ASCII CR (&#039;&#039;&#039;0x0D&#039;&#039;&#039;, &#039;&#039;&#039;\r&#039;&#039;&#039;), &#039;&#039;&#039;espaço&#039;&#039;&#039; ASCII SP (&#039;&#039;&#039;0x20&#039;&#039;&#039;, ⌴) e &#039;&#039;&#039;tabulação horizontal&#039;&#039;&#039; ASCII HT (&#039;&#039;&#039;0x09&#039;&#039;&#039;, &#039;&#039;&#039;\t&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Comentários ==&lt;br /&gt;
&lt;br /&gt;
Existem dois tipos de comentários, que também funcionam como elementos separadores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;explicativos&#039;&#039;&#039; -- começam com &#039;&#039;&#039;//&#039;&#039;&#039; e acabam no fim da linha; e&lt;br /&gt;
* &#039;&#039;&#039;operacionais&#039;&#039;&#039; -- começam com &#039;&#039;&#039;/*&#039;&#039;&#039; e terminam com &#039;&#039;&#039;*/&#039;&#039;&#039;, podendo estar aninhados.&lt;br /&gt;
&lt;br /&gt;
Se as sequências de início fizerem parte de uma cadeia de caracteres, não iniciam um comentário (ver [[#Cadeias de caracteres|definição das cadeias de caracteres]]).&lt;br /&gt;
&lt;br /&gt;
== Palavras-chave ==&lt;br /&gt;
&lt;br /&gt;
As seguintes palavras-chave são reservadas, não constituindo identificadores (devem ser escritas exactamente como indicado):&lt;br /&gt;
&lt;br /&gt;
* tipos: &#039;&#039;&#039;int real string void&#039;&#039;&#039;&lt;br /&gt;
* declarações: &#039;&#039;&#039;extern forward public auto&#039;&#039;&#039;&lt;br /&gt;
* instruções: &#039;&#039;&#039;if elif else while stop next return&#039;&#039;&#039;&lt;br /&gt;
* expressões: &#039;&#039;&#039;input null sizeof&#039;&#039;&#039;&lt;br /&gt;
* outras: &#039;&#039;&#039;begin end&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tipos ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais designam tipos em declarações (ver gramática): &#039;&#039;&#039;int&#039;&#039;&#039; (inteiro), &#039;&#039;&#039;real&#039;&#039;&#039; (real), &#039;&#039;&#039;string&#039;&#039;&#039; (cadeia de caracteres). &lt;br /&gt;
&lt;br /&gt;
Os tipos correspondentes a ponteiros são outros tipos delimitados por &#039;&#039;&#039;[&#039;&#039;&#039; e &#039;&#039;&#039;]&#039;&#039;&#039;, designando uma indirecção e não o objecto directo (ver gramática).&lt;br /&gt;
&lt;br /&gt;
Note-se que, quando se tem uma declaração &#039;&#039;&#039;extern&#039;&#039;&#039;, os tipos correspondem aos compatíveis com a linguagem C na mesma arquitectura ix86 de 32 bits, i.e., &#039;&#039;&#039;int&#039;&#039;&#039; corresponde a  um número binário inteiro em [https://en.wikipedia.org/wiki/Two%27s_complement complemento para 2] (32 bits), &#039;&#039;&#039;real&#039;&#039;&#039; coresponde a uma representação segundo a norma [https://en.wikipedia.org/wiki/IEEE_754 IEEE 754] de dupla precisão (64 bits), devendo ser convertidos de e para os tipos nativos da linguage P6 sempre que necessário (ver RTS).&lt;br /&gt;
&lt;br /&gt;
== Operadores de expressões ==&lt;br /&gt;
&lt;br /&gt;
São considerados operadores os elementos lexicais apresentados na definição das expressões.&lt;br /&gt;
&lt;br /&gt;
== Delimitadores e terminadores ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais são delimitadores/terminadores: &lt;br /&gt;
* &#039;&#039;&#039;,&#039;&#039;&#039; (vírgula)&lt;br /&gt;
* &#039;&#039;&#039;;&#039;&#039;&#039; (ponto e vírgula)&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; (operações de impressão)&lt;br /&gt;
* &#039;&#039;&#039;(&#039;&#039;&#039; e &#039;&#039;&#039;)&#039;&#039;&#039; (delimitadores de expressões)&lt;br /&gt;
* &#039;&#039;&#039;{&#039;&#039;&#039; e &#039;&#039;&#039;}&#039;&#039;&#039; (delimitadores de blocos)&lt;br /&gt;
&lt;br /&gt;
== Identificadores (nomes) ==&lt;br /&gt;
&lt;br /&gt;
São iniciados por uma letra, seguindo-se 0 (zero) ou mais letras ou dígitos. 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.&lt;br /&gt;
&lt;br /&gt;
== Literais ==&lt;br /&gt;
&lt;br /&gt;
São notações para valores constantes de alguns tipos da linguagem (não confundir com constantes, i.e., identificadores que, em algumas linguagens, designam elementos cujo valor não pode ser alterado durante a execução do programa).&lt;br /&gt;
&lt;br /&gt;
=== Inteiros ===&lt;br /&gt;
&lt;br /&gt;
Um literal inteiro é um número não negativo (mas ver a seguir). Números negativos podem ser construídos pela aplicação do operador de negação unária (&#039;&#039;&#039;-&#039;&#039;&#039;) a um literal (sempre positivo).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros decimais são constituídos por sequências de 1 (um) ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;9&#039;&#039;&#039;, em que o primeiro digito não é 0 (zero), excepto no caso do número 0 (zero). Neste caso, é composto apenas pelo dígito 0 (zero) (em qualquer base).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 9 começam sempre pelo dígito 0 (zero), sendo seguidos de um ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;8&#039;&#039;&#039; (note-se que &#039;&#039;&#039;09&#039;&#039;&#039; é um literal inválido em base 9). Exemplo: &#039;&#039;&#039;086 = 78&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 3 (equilibrada) começam sempre com a sequência &#039;&#039;&#039;0t&#039;&#039;&#039;, seguida de um ou mais símbolos dessa base: &#039;&#039;&#039;-&#039;&#039;&#039; (valor &#039;&#039;&#039;-1&#039;&#039;&#039;), &#039;&#039;&#039;0&#039;&#039;&#039; (valor &#039;&#039;&#039;0&#039;&#039;&#039;) e &#039;&#039;&#039;+&#039;&#039;&#039; (valor &#039;&#039;&#039;1&#039;&#039;&#039;). Estes literais podem ser intrinsecamente negativos. Exemplos: &#039;&#039;&#039;0t+0-0 = 24&#039;&#039;&#039;; &#039;&#039;&#039;0t-0+0 = -24&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Se não for possível representar um literal na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
&lt;br /&gt;
=== Reais em formato Takum3 ===&lt;br /&gt;
&lt;br /&gt;
Os literais reais (sempre positivos) são expressos tal como em C (exclusivamente em base 10). &lt;br /&gt;
&lt;br /&gt;
Não existem literais negativos (números negativos resultam da operação unária &#039;&#039;&#039;-&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Note-se que um literal sem &#039;&#039;&#039;.&#039;&#039;&#039; (ponto decimal) nem parte exponencial é do tipo inteiro.&lt;br /&gt;
&lt;br /&gt;
Note-se que, apesar de C normalmente usar uma representação interna em binário no formato IEEE 754, a linguagem P6 usa um formato, representado em ternário, completamente diferente (embora a forma de escrita dos literais seja a mesma).&lt;br /&gt;
&lt;br /&gt;
Exemplos: &#039;&#039;&#039;3.14&#039;&#039;&#039;, &#039;&#039;&#039;1E3&#039;&#039;&#039; = 1000 (número inteiro representado como real). &#039;&#039;&#039;12.34e-24&#039;&#039;&#039; = 12.34 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; (notação cientifica).&lt;br /&gt;
&amp;lt;!--Se não for possível representar um literal real na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cadeias de caracteres ===&lt;br /&gt;
&lt;br /&gt;
As cadeias de caracteres são delimitadas por aspas (&#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;) e podem conter quaisquer caracteres, excepto ASCII NUL (0x00) e ASCII LF (0x0A). Nas cadeias, os delimitadores de comentários não têm significado especial. Se for escrito um literal que contenha &#039;&#039;&#039;\0&#039;&#039;&#039;, então a cadeia termina nessa posição. Exemplo: &#039;&#039;&#039;ab\0xy&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;ab&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
É possível designar caracteres por sequências especiais (iniciadas por &#039;&#039;&#039;\&#039;&#039;&#039;), especialmente úteis quando não existe representação gráfica directa. As sequências especiais correspondem aos caracteres ASCII HT, LF e CR (&#039;&#039;&#039;\t&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039; e &#039;&#039;&#039;\r&#039;&#039;&#039;, respectivamente), aspa (&#039;&#039;&#039;\&amp;quot;&#039;&#039;&#039;). &#039;&#039;backslash&#039;&#039; (&#039;&#039;&#039;\\&#039;&#039;&#039;), ou a quaisquer outros especificados através de 1 a 3 dígitos em base 8, designando valores de 8 bits (e.g., &#039;&#039;&#039;\012&#039;&#039;&#039; ou apenas &#039;&#039;&#039;\12&#039;&#039;&#039; se o carácter seguinte não representar um dígito em base 8). Exemplo: &#039;&#039;&#039;xy\012z&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;xy\12z&#039;&#039;&#039; e que &#039;&#039;&#039;xy\nz&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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: &#039;&#039;&#039;&amp;quot;ab&amp;quot;&#039;&#039;&#039; &#039;&#039;&#039;&amp;quot;cd&amp;quot;&#039;&#039;&#039; é o mesmo que &#039;&#039;&#039;&amp;quot;abcd&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Ponteiros ===&lt;br /&gt;
&lt;br /&gt;
O único literal admissível para ponteiros corresponde ao ponteiro nulo e é indicado pela palavra-chave &#039;&#039;&#039;null&#039;&#039;&#039;. Este literal é compatível com todos os tipos de ponteiro. Os inteiros não são convertíveis em ponteiros, pelo que o valor &#039;&#039;&#039;0&#039;&#039;&#039; (zero) não é um valor inicial admissível para ponteiros.&lt;br /&gt;
&lt;br /&gt;
Note-se que a aritmética de ponteiros é possível apenas com inteiros binários, mas não com inteiros ternários (estes devem ser convertidos para binário, caso seja necessário).&lt;br /&gt;
&lt;br /&gt;
= Gramática =&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; e &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;. Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! style=&amp;quot;width: 140px; font-weight: normal;&amp;quot; | &#039;&#039;ficheiro&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;programa-principal&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;declaração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;tipo&#039;&#039; &#039;&#039;identificador&#039;&#039; [ &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] [ &#039;&#039;&#039;auto&#039;&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;função&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;programa-principal&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;begin&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;end&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;variáveis&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;variáveis&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;int&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;real&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;string&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;void&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;[&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;]&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;tipos&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipos&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;{&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;}&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!!&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;stop&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;next&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;return&#039;&#039;&#039; [ &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;instrução-condicional&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;instrução-de-iteração&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-condicional&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;if&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt;  &#039;&#039;&#039;elif&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;&#039;else&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-de-iteração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;while&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;expressões&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tipos, identificadores, literais e definição de expressões ==&lt;br /&gt;
&lt;br /&gt;
Algumas definições foram omitidas da gramática: tipos de dados. qualificadores e variável (ver [[#Declarações de variáveis|declarações de variáveis]]), identificador (ver [[#Identificadores (nomes)|identificadores]]), literal (ver [[#Literais|literais]]); expressão (ver [[#Expressões|expressões]]). &amp;lt;!--Note-se que &#039;&#039;função&#039;&#039; é qualquer especificação de função (corpo ou ponteiro com o tipo apropriado). Neste sentido, as funções contam como expressões primitivas.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Quanto a tipos de dados, &#039;&#039;&#039;int&#039;&#039;&#039; designa valores inteiros, &#039;&#039;&#039;real&#039;&#039;&#039; designa valores reais, &#039;&#039;&#039;string&#039;&#039;&#039; designa cadeias de caracteres. Os ponteiros são tipos compostos por um tipo entre parênteses rectos, e.g., &#039;&#039;&#039;[int]&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Os tipos funcionais são definidos a partir dos tipos de dados anteriormente descritos e do tipo especial &#039;&#039;&#039;void&#039;&#039;&#039; (ver a seguir). O tipo é indicado com o formato indicado na gramática, i.e., tipo de retorno seguido dos tipos dos argumentos (zero ou mais separados por vírgulas). Estes tipos servem para declarar símbolos de função sem as definir.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Um ponteiro declarado com um tipo de função indica o endereço da função correspondente. Estes ponteiros não suportam aritmética de ponteiros.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
O tipo &#039;&#039;&#039;void&#039;&#039;&#039; apenas pode ser usado para indicar a ausência de retorno ou para declarar um ponteiro genérico. Neste caso, o aninhamento é irrelevante, i.e., &#039;&#039;&#039;[void]&#039;&#039;&#039; e &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[void]]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; são equivalentes. Um ponteiro deste tipo é compatível com todos os outros tipos de ponteiros. A aritmética de ponteiros decrementa/incrementa em uma unidade o valor de um ponteiro do tipo &#039;&#039;&#039;[void]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Left-values ==&lt;br /&gt;
&lt;br /&gt;
Os &#039;&#039;left-values&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
== Ficheiros ==&lt;br /&gt;
&lt;br /&gt;
Um ficheiro é designado por principal se contiver a função principal (onde se inicia o programa).&lt;br /&gt;
&lt;br /&gt;
== Declaração de variáveis ==&lt;br /&gt;
&lt;br /&gt;
Uma declaração de variável indica sempre um tipo de dados (implícito ou explícito) e um identificador.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
&lt;br /&gt;
* Inteiro: &#039;&#039;&#039;int i&#039;&#039;&#039;&lt;br /&gt;
* Real: &#039;&#039;&#039;real r&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres: &#039;&#039;&#039;string s&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro para inteiro: &#039;&#039;&#039;[int] p1&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para real: &#039;&#039;&#039;[real] p2&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;double*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para cadeia de caracteres: &#039;&#039;&#039;[string] p3&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;char**&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para ponteiro para inteiro: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[int]]&amp;lt;/nowiki&amp;gt; p4&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int**&#039;&#039;&#039; em C)&lt;br /&gt;
&lt;br /&gt;
É possível usar o pseudo-tipo &#039;&#039;&#039;auto&#039;&#039;&#039; se a declaração tiver um valor inicial: neste caso, o tipo é o do valor inicial.&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
* Variável inteira: &#039;&#039;&#039;auto i = 1&#039;&#039;&#039;&lt;br /&gt;
* Variável real: &#039;&#039;&#039;auto f = 2.0&#039;&#039;&#039;&lt;br /&gt;
* etc.&lt;br /&gt;
&lt;br /&gt;
== Símbolos globais ==&lt;br /&gt;
&lt;br /&gt;
Por omissão, os símbolos são privados a um módulo, não podendo ser importados por outros módulos.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;public&#039;&#039;&#039; permite declarar um identificador como público, tornando-o acessível a partir de outros módulos. Quando usado com a palavra-chave &#039;&#039;&#039;auto&#039;&#039;&#039;, esta é opcional. Note-se que a declaração de uma variável tem de ter sempre, ou o qualificador, ou o tipo, podendo estar ambos presentes.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;forward&#039;&#039;&#039; permite declarar num módulo variáveis ou funções definidas noutros módulos. Neste caso, não pode ser especificado o valor inicial das variáveis, pelo que não é possível o uso de &#039;&#039;&#039;auto&#039;&#039;&#039; em conjunto com &#039;&#039;&#039;forward&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;extern&#039;&#039;&#039; deve ser usada para declarar símbolos de função com tipos diferentes dos dos nativos da da linguagem P6, e.g. para importar funções definidas em C. Além de poderem ser usados para chamar as funções que designam, os símbolos assim declarados podem ser utilizados com valores convertidos de forma apropriada.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Declarar variável privada ao módulo: &#039;&#039;&#039;real r1 = 22.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public real r2 = 7.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public auto r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Usar definição externa de variável pública: &#039;&#039;&#039;forward real r2&#039;&#039;&#039;&lt;br /&gt;
* Declarar função (nativa P6) definida externamente: &#039;&#039;&#039;forward int&amp;lt;int&amp;gt; factorial&#039;&#039;&#039;&lt;br /&gt;
* Declarar função definida noutra linguagem (e.g. em C): &#039;&#039;&#039;extern [void]&amp;lt;int&amp;gt; malloc&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inicialização ==&lt;br /&gt;
&lt;br /&gt;
Quando existe, é a designação do objecto que segue o símbolo &#039;&#039;&#039;=&#039;&#039;&#039;: inteiro, real, cadeia de caracteres, ou 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.&amp;lt;!-- A associação de valores funcionais a variáveis pode ser realizada quando os tipos forem covariantes. As cadeias de caracteres são (possivelmente) inicializadas com uma lista não nula de valores sem separadores.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A palavra &#039;&#039;&#039;auto&#039;&#039;&#039; pode ser usada em lugar do tipo para declarar uma variável. Quando usada, o tipo da variável é inferido a partir do valor inicial (nestes casos, o valor inicial é obrigatório).&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Inteiro (literal): &#039;&#039;&#039;int i = 3&#039;&#039;&#039;&lt;br /&gt;
* Inteiro (expressão): &#039;&#039;&#039;int i = j + 1&#039;&#039;&#039;&lt;br /&gt;
* Real (literal): &#039;&#039;&#039;real r = 3.2&#039;&#039;&#039;&lt;br /&gt;
* Real (expressão): &#039;&#039;&#039;real r = i - 2.5&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literal): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literais): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot; &amp;quot;mãe&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (literal): &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[real]]] p&amp;lt;/nowiki&amp;gt; = null&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (expressão): &#039;&#039;&#039;[int] p = q + 1&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;!--* Função:&lt;br /&gt;
 int&amp;lt;int&amp;gt; f1&lt;br /&gt;
 int&amp;lt;real&amp;gt; g1&lt;br /&gt;
 real&amp;lt;int&amp;gt; g2&lt;br /&gt;
 int&amp;lt;int&amp;gt; f2 = f1  // ok: mesmo tipo&lt;br /&gt;
 f2 = g1 // ok: tipos covariantes&lt;br /&gt;
 f2 = g2 // ERRADO&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Funções =&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Declaração ==&lt;br /&gt;
&lt;br /&gt;
As funções têm um nome que é também o endereço dessa função. O tipo de retorno de uma função que não produz valores de retorno é &#039;&#039;&#039;void&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
As funções que recebam argumentos devem indicá-los no cabeçalho. Funções sem argumentos definem um cabeçalho vazio. Os qualificadores de exportação/importação &#039;&#039;&#039;public&#039;&#039;&#039; ou &#039;&#039;&#039;forward&#039;&#039;&#039; (ver símbolos globais) podem ser aplicados às funções, mas não é possível aplicá-los às declarações dos argumentos de uma função. Não é possível especificar valores por omissão para os argumentos de uma função, nem para o valor de retorno.&lt;br /&gt;
&lt;br /&gt;
A declaração de um ponteiro para uma função (ou, de forma equivalente, do seu nome) é utilizada para caracterizar 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). &amp;lt;!--Caso a declaração tenha corpo, define-se uma nova função.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Invocação ==&lt;br /&gt;
&lt;br /&gt;
Uma função pode ser invocada através do seu nome. &amp;lt;!--ou de um ponteiro do tipo apropriado que refira essa função (ponteiro não nulo). O símbolo &#039;&#039;&#039;@&#039;&#039;&#039; pode ser usado dentro da própria função para efectuar uma invocação recursiva. Não é possível o uso de &#039;&#039;&#039;@&#039;&#039;&#039; no programa principal.--&amp;gt;&lt;br /&gt;
Se existirem argumentos, na invocação da função, o nome é 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 menos de conversões implícitas). A ordem dos parâmetros actuais deverá ser a mesma dos argumentos formais da função a ser invocada.&lt;br /&gt;
&lt;br /&gt;
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. Note que o retorno de entidades com dimensão superior a 64 bits deve fazer-se através da reserva de espaço para o retorno no chamador e passando um ponteiro para esse espaço como primeiro argumento do chamado.&lt;br /&gt;
&lt;br /&gt;
== Corpo ==&lt;br /&gt;
&lt;br /&gt;
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 de exportação (&#039;&#039;&#039;public&#039;&#039;&#039;) ou de importação (&#039;&#039;&#039;forward&#039;&#039;&#039; ou &#039;&#039;&#039;extern&#039;&#039;&#039;) (ver [[#Símbolos globais|símbolos globais]]) dentro do corpo de uma função.&lt;br /&gt;
&lt;br /&gt;
Uma instrução &#039;&#039;&#039;return&#039;&#039;&#039; causa a interrupção da função. O valor devolvido por uma função, através de expressão usada como argumento da instrução &#039;&#039;&#039;return&#039;&#039;&#039;, deve ser do tipo declarado no cabeçalho da função. Ver casos especiais acima.&lt;br /&gt;
&lt;br /&gt;
É um erro especificar um valor de retorno se a função for declarada como não retornando um valor (indicada como &#039;&#039;&#039;void&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Qualquer bloco (usado, por exemplo, numa instrução condicional ou de iteração) pode definir variáveis locais. &amp;lt;!--, cujos valores podem ser outras funções. Funções definidas dentro de um bloco não têm acesso às variáveis em contexto na função actual onde ocorrem.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Função principal e execução de programas ==&lt;br /&gt;
&lt;br /&gt;
Um programa é a sequência de instruções que seguem as declarações globais num ficheiro, delimitadas pelas palavras-chave &#039;&#039;&#039;begin&#039;&#039;&#039; e &#039;&#039;&#039;end&#039;&#039;&#039;. Esta sequência forma o que em algumas linguagens se chama a função principal. Os argumentos com que o programa foi chamado podem ser obtidos através de funções &#039;&#039;&#039;argc&#039;&#039;&#039; (devolve o número de argumentos); &#039;&#039;&#039;argv&#039;&#039;&#039; (devolve o n-ésimo argumento como uma cadeia de caracteres, com n&amp;gt;0); e &#039;&#039;&#039;envp&#039;&#039;&#039; (devolve a n-ésima variável de ambiente como uma cadeia de caracteres, com n&amp;gt;0). Apenas um dos módulos do programa pode definir a função principal, i.e., se existirem vários módulos, apenas um deles pode conter mais do que declarações de variáveis globais.&lt;br /&gt;
&lt;br /&gt;
 extern int&amp;lt;&amp;gt; argc&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; argv&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; envp&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
= Instruções =&lt;br /&gt;
&lt;br /&gt;
Excepto quando indicado, as instruções são executadas em sequência.&lt;br /&gt;
&lt;br /&gt;
== Blocos ==&lt;br /&gt;
&lt;br /&gt;
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 definir funções dentro de blocos, mas é possível declarar ponteiros de função locais.&lt;br /&gt;
&lt;br /&gt;
A visibilidade das variáveis é limitada ao bloco em que foram declaradas. As entidades declaradas podem ser directamente utilizadas em sub-blocos ou passadas como argumentos para funções chamadas dentro do bloco. Caso os identificadores usados para definir as variáveis locais já estejam a ser utilizados para definir outras entidades ao alcance do bloco, o novo identificador passa a referir uma nova entidade definida no bloco até que ele termine (a entidade previamente definida continua a existir, mas não pode ser directamente referida pelo seu nome). Esta regra é também válida relativamente a&lt;br /&gt;
argumentos de funções (ver corpo das funções).&lt;br /&gt;
&lt;br /&gt;
== Instrução condicional ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento semelhante ao da instrução &#039;&#039;&#039;if-else&#039;&#039;&#039; em C. As partes correspondentes a &#039;&#039;&#039;elif&#039;&#039;&#039; comportam-se como encadeamentos de instruções condicionais na parte &#039;&#039;&#039;else&#039;&#039;&#039; de um &#039;&#039;&#039;if-else&#039;&#039;&#039; à la C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de iteração ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento idêntico ao da instrução &#039;&#039;&#039;while&#039;&#039;&#039; em C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de terminação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;stop&#039;&#039;&#039; termina o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;break&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de continuação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;next&#039;&#039;&#039; reinicia o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;continue&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de retorno ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;return&#039;&#039;&#039;, se existir, é a última instrução do seu bloco. Ver comportamento na [[#Corpo|descrição do corpo de uma função]].&lt;br /&gt;
&lt;br /&gt;
== Expressões como instruções ==&lt;br /&gt;
&lt;br /&gt;
As expressões utilizadas como instruções são sempre avaliadas, mesmo que não produzam efeitos secundários.&lt;br /&gt;
&lt;br /&gt;
== Instruções de impressão ==&lt;br /&gt;
&lt;br /&gt;
As notações &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; podem ser utilizadas para apresentar valores na saída do programa. A primeira forma apresenta os valores sem mudar de linha; a segunda forma apresenta os valores mudando de linha depois de os apresentar a todos. Quando existe mais de uma expressão, as várias expressões são apresentadas sem separação. Valores numéricos (inteiros ou reais) são impressos em decimal. As cadeias de caracteres são impressas na codificação nativa. Ponteiros não podem ser impressos.&lt;br /&gt;
&lt;br /&gt;
= Expressões =&lt;br /&gt;
&lt;br /&gt;
Uma expressão é uma representação algébrica de uma quantidade: todas as expressões têm um tipo e devolvem um valor.&lt;br /&gt;
&lt;br /&gt;
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]].&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
 {|&lt;br /&gt;
| &#039;&#039;&#039;Tipo de Expressão&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operadores&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Associatividade&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operandos&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Semântica&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| primária&lt;br /&gt;
| &#039;&#039;&#039;( ) [ ]&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Parênteses curvos|parênteses curvos]], [[#Indexação|indexação]], [[#Reserva de memória|reserva de memória]]&lt;br /&gt;
|-&lt;br /&gt;
| unária&lt;br /&gt;
| &#039;&#039;&#039;+ - ?&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Identidade e simétrico|identidade e simétrico]], [[#Expressão de indicação de posição|indicação de posição]]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;não&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;~&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | não associativo&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: negação&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | multiplicativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;* / %&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | aditiva&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;+ -&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias: se envolverem ponteiros, calculam: (i) deslocamentos, i.e., um dos operandos deve ser do tipo ponteiro e o outro do tipo inteiro (binário de 32 bits); (ii) diferenças de ponteiros, i.e., apenas quando se aplica o operador &#039;&#039;&#039;-&#039;&#039;&#039; a dois ponteiros do mesmo tipo (o resultado é o número de objectos do tipo apontado entre eles, representado como um valor inteiro ternário de 64 bits). Se a memória não for contígua, o resultado é indefinido.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | comparativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt; &amp;gt; &amp;lt;= &amp;gt;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | igualdade&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;== !=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;e&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for falso.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;ou&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for verdadeiro.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | atribuição&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da direita para a esquerda&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | todos os tipos&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | O valor da expressão do lado direito do operador é guardado na posição indicada pelo &#039;&#039;left-value&#039;&#039; (operando esquerdo do operador). Podem ser atribuídos valores inteiros a &#039;&#039;left-values&#039;&#039; reais (conversão automática). Nos outros casos, ambos os tipos têm de concordar. O literal &#039;&#039;&#039;null&#039;&#039;&#039; é compatível com todos os tipos de ponteiros.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Expressões primitivas ==&lt;br /&gt;
&lt;br /&gt;
As [[#Literais|expressões literais]] e a [[#Invocação|invocação de funções]] foram definidas acima.&lt;br /&gt;
&lt;br /&gt;
=== Identificadores ===&lt;br /&gt;
&lt;br /&gt;
Um identificador é uma expressão se tiver sido declarado. Um identificador pode denotar uma variável.&lt;br /&gt;
&lt;br /&gt;
Um identificador é o caso mais simples de um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;, ou seja, uma entidade que pode ser utilizada no lado esquerdo (&#039;&#039;left&#039;&#039;) de uma atribuição.&lt;br /&gt;
&lt;br /&gt;
=== Leitura ===&lt;br /&gt;
&lt;br /&gt;
A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão indicada pela palavra-chave &#039;&#039;&#039;input&#039;&#039;&#039;, que devolve o valor lido, de acordo com o tipo esperado (inteiro ou real). Caso se use como argumento dos operadores de impressão ou noutras situações que permitam vários tipos (e.g. &#039;&#039;&#039;!&#039;&#039;&#039; ou &#039;&#039;&#039;!!&#039;&#039;&#039;), deve ser lido um inteiro.&lt;br /&gt;
&lt;br /&gt;
Exemplos:  &#039;&#039;&#039;a = input&#039;&#039;&#039; (leitura para &#039;&#039;&#039;a&#039;&#039;&#039;), &#039;&#039;&#039;f(input)&#039;&#039;&#039; (leitura para argumento de função), &#039;&#039;&#039;input!!&#039;&#039;&#039; (leitura e impressão).&lt;br /&gt;
&lt;br /&gt;
=== Parênteses curvos ===&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;left-value&#039;&#039; (ver também a [[#Indexação|expressão de indexação]]).&lt;br /&gt;
&amp;lt;!--=== Funções ===&lt;br /&gt;
&lt;br /&gt;
As funções (ponteiros ou o seu código: não confundir com chamadas a funções) podem ser usadas como expressões tipificadas como funções, i.e., ponteiros para funções (mesmo quando não se usa explicitamente um ponteiro).&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
 f1(int i) -&amp;gt; int { return i + 1; }&lt;br /&gt;
 f2(int i) -&amp;gt; int { return i * 2; }&lt;br /&gt;
&lt;br /&gt;
 g(int n, int&amp;lt;int&amp;gt; fun) -&amp;gt; int { return fun(n); }&lt;br /&gt;
 &lt;br /&gt;
 begin&lt;br /&gt;
   g(3, f1)!!  // escreve 4&lt;br /&gt;
   g(3, f2)!!  // escreve 6&lt;br /&gt;
 end&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expressões resultantes de avaliação de operadores ==&lt;br /&gt;
&lt;br /&gt;
=== Indexação de ponteiros ===&lt;br /&gt;
&lt;br /&gt;
A indexação de ponteiros devolve o valor de uma posição de memória indicada por um ponteiro. Consiste em uma expressão ponteiro seguida do índice entre parênteses rectos. O resultado de uma indexação de ponteiros é um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;. Não é possível indexar ponteiros que designem funções.&lt;br /&gt;
&lt;br /&gt;
Exemplo (acesso à posição 0 da zona de memória indicada por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;p[0]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Identidade e simétrico ===&lt;br /&gt;
&lt;br /&gt;
Os operadores identidade (&#039;&#039;&#039;+&#039;&#039;&#039;) e simétrico (&#039;&#039;&#039;-&#039;&#039;&#039;) aplicam-se a inteiros e reais. Têm o mesmo significado que em análogo às operações correspondentes em C, mas operam sobre grandezas ternárias.&lt;br /&gt;
&lt;br /&gt;
=== Reserva de memória ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Exemplo (reserva vector com 5 reais, apontados por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;[real] p = [5]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de indicação de posição ===&lt;br /&gt;
&lt;br /&gt;
O operador sufixo &#039;&#039;&#039;?&#039;&#039;&#039; aplica-se a &#039;&#039;left-values&#039;&#039;, retornando o endereço (com o tipo ponteiro) correspondente.&lt;br /&gt;
&lt;br /&gt;
Exemplo (indica o endereço de &#039;&#039;&#039;a&#039;&#039;&#039;): &#039;&#039;&#039;a?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de dimensão ===&lt;br /&gt;
&lt;br /&gt;
O operador &#039;&#039;&#039;sizeof&#039;&#039;&#039; tem um único argumento e aplica-se a expressões, retornando a dimensão correspondente em bytes.&lt;br /&gt;
&lt;br /&gt;
Exemplo: &#039;&#039;&#039;sizeof(a)&#039;&#039;&#039; (dimensão de &#039;&#039;&#039;a&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
= Exemplos e Testes =&lt;br /&gt;
&lt;br /&gt;
Os exemplos abaixo não são exaustivos e não ilustram todos os aspectos da linguagem.&lt;br /&gt;
&lt;br /&gt;
Estão ainda disponíveis outros [https://gitlab.rnl.tecnico.ulisboa.pt/leic-a-co26/eval/co26 pacotes de testes].&lt;br /&gt;
&lt;br /&gt;
O seguinte exemplo ilustra um programa com dois módulos: um que define a função &#039;&#039;&#039;factorial&#039;&#039;&#039; e outro que define a função principal.&lt;br /&gt;
&lt;br /&gt;
Definição da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;factorial.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
public factorial(int n) -&amp;gt; int {&lt;br /&gt;
  if (n &amp;gt; 1) &lt;br /&gt;
    return n * factorial(n - 1);&lt;br /&gt;
  else &lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exemplo da utilização da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;main.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
// external builtin functions (non-P6)&lt;br /&gt;
extern int&amp;lt;&amp;gt; argc;&lt;br /&gt;
extern string&amp;lt;int&amp;gt; argv;&lt;br /&gt;
extern int&amp;lt;string&amp;gt; atoi;&lt;br /&gt;
&lt;br /&gt;
// external user functions (P6)&lt;br /&gt;
forward int&amp;lt;int&amp;gt; factorial;&lt;br /&gt;
&lt;br /&gt;
// the main function&lt;br /&gt;
begin&lt;br /&gt;
  auto value = 1;&lt;br /&gt;
  &amp;quot;Teste para a função factorial.&amp;quot;!!&lt;br /&gt;
  if (argc() == 2) {&lt;br /&gt;
    string s = argv(1);&lt;br /&gt;
    value = atoi(s);&lt;br /&gt;
  }&lt;br /&gt;
  value, &amp;quot;! é &amp;quot;, factorial(value)!!&lt;br /&gt;
  return 0;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Como compilar:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
p6 --target asm factorial.p6&lt;br /&gt;
p6 --target asm main.p6&lt;br /&gt;
yasm -felf32 factorial.asm&lt;br /&gt;
yasm -felf32 main.asm&lt;br /&gt;
ld -melf_i386 -o main factorial.o main.o -lrts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Omissões e Erros =&lt;br /&gt;
&lt;br /&gt;
Casos omissos e erros serão corrigidos em futuras versões do manual de referência.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Code_Generation&amp;diff=17788</id>
		<title>Code Generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Code_Generation&amp;diff=17788"/>
		<updated>2026-05-18T15:26:47Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
== Topics ==&lt;br /&gt;
* Interpretation: syntax-directed and based on abstract syntax tree.&lt;br /&gt;
* Code generation: syntax-directed and based on abstract syntax tree.&lt;br /&gt;
&lt;br /&gt;
The approach described here is based on generation from the intermediate representation in the form of an abstract syntax tree formed by the nodes created during the parsing process.&lt;br /&gt;
&lt;br /&gt;
The target machine is the Postfix engine described below.&lt;br /&gt;
&lt;br /&gt;
== The Postfix Machine ==&lt;br /&gt;
&lt;br /&gt;
The Postfix machine is a stack machine possessing a single large stack and 0-operand instructions (SL0).&lt;br /&gt;
&lt;br /&gt;
Three special purpose registers: IP (instruction pointer, a.k.a, program counter), for jumps and function calls; FP (frame pointer, a.k.a. base pointer), the basis of the frame pointer for each function; SP (stack pointer), keeps track of the top of the stack.&lt;br /&gt;
&lt;br /&gt;
The stack grows in the direction of lower addresses.&lt;br /&gt;
&lt;br /&gt;
Almost all operations use the stack as input and output (exceptions are instructions for returning values from functions in accordance with CDecl), and instructions that use either immediate arguments or arguments in global memory (i.e., with explicit named addressing).&lt;br /&gt;
&lt;br /&gt;
The [[Postfix Reference Guide|Postfix reference guide]] contains further details about the Postfix machine and its operations.&lt;br /&gt;
&lt;br /&gt;
== Basic Structures (code) ==&lt;br /&gt;
&lt;br /&gt;
The mnemonics are those of the Postfix language. Comments indicate missing parts.&lt;br /&gt;
&lt;br /&gt;
=== Cycles ===&lt;br /&gt;
&lt;br /&gt;
Basic structure of a &#039;&#039;&#039;while&#039;&#039;&#039; cycle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
LABEL condition&lt;br /&gt;
;; evaluate condition expression&lt;br /&gt;
JZ endcycle&lt;br /&gt;
;; evaluate block&lt;br /&gt;
JMP condition&lt;br /&gt;
LABEL endcycle&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basic structure of a &#039;&#039;&#039;do-while&#039;&#039;&#039; cycle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
LABEL startcycle&lt;br /&gt;
;; evaluate block&lt;br /&gt;
LABEL condition&lt;br /&gt;
;; evaluate condition expression&lt;br /&gt;
JNZ startcycle&lt;br /&gt;
LABEL endcycle&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basic structure of a C-style &#039;&#039;&#039;for&#039;&#039;&#039; cycle:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; evaluate initializer&lt;br /&gt;
LABEL condition&lt;br /&gt;
;; evaluate condition expression&lt;br /&gt;
JZ endfor&lt;br /&gt;
;; evaluate block&lt;br /&gt;
LABEL increment&lt;br /&gt;
;; evaluate increment expression&lt;br /&gt;
JMP condition&lt;br /&gt;
LABEL endfor&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;quot;Break&amp;quot; and &amp;quot;Continue&amp;quot; Instructions ===&lt;br /&gt;
&lt;br /&gt;
The C-style &#039;&#039;&#039;break&#039;&#039;&#039; and &#039;&#039;&#039;continue&#039;&#039;&#039; instructions must jump, respectively, to the end of the cycle or to its condition (for deciding on whether to execute the next iteration). In the case of &#039;&#039;&#039;for&#039;&#039;&#039; cycles, the jump to the condition is not direct, but rather via a jump to the increment label.&lt;br /&gt;
&lt;br /&gt;
If there are multiple nested cycles, the code generator must keep track of the innermost one, so that it can generate the appropriate jumps. This can be achieved through the use of address stacks (one for &#039;&#039;&#039;break&#039;&#039;&#039; labels and another for &#039;&#039;&#039;continue&#039;&#039;&#039; labels).&lt;br /&gt;
&lt;br /&gt;
=== If-Then and If-Then-Else Instructions ===&lt;br /&gt;
&lt;br /&gt;
Basic structure of an &amp;quot;if-then&amp;quot; instruction:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; evaluate condition expression&lt;br /&gt;
JZ endif&lt;br /&gt;
;; evaluate then block&lt;br /&gt;
LABEL endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basic structure of an &amp;quot;if-then-else&amp;quot; instruction:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; evaluate condition expression&lt;br /&gt;
JZ else&lt;br /&gt;
;; evaluate then block&lt;br /&gt;
JMP endif&lt;br /&gt;
LABEL else&lt;br /&gt;
;; evaluate else block&lt;br /&gt;
LABEL endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Functions ===&lt;br /&gt;
&lt;br /&gt;
The function structure presented here assumes a &amp;quot;void&amp;quot; return. If a return were desired, the use of STFVAL32 or STFVAL64 would be required before the LEAVE instruction.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;sizeoflocalvars&amp;quot; is the number of bytes needed to store all of the function&#039;s local variables. If this value is 0 (zero), START may be used instead of ENTER.&lt;br /&gt;
&lt;br /&gt;
If the function is not global (e.g. C-style &amp;quot;static&amp;quot; function), then GLOBAL should not be used.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
GLOBAL functionname,FUNC&lt;br /&gt;
LABEL functionname&lt;br /&gt;
ENTER sizeoflocalvars&lt;br /&gt;
;; evaluate function body&lt;br /&gt;
LEAVE&lt;br /&gt;
RET&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Basic Structures (data) ==&lt;br /&gt;
&lt;br /&gt;
=== Defining global (permanent) variables ===&lt;br /&gt;
&lt;br /&gt;
We include in this category C-like &amp;quot;static&amp;quot; function variables (the only difference is that they are not defined with their explicit names, but rather with a name that reflects their being visible only inside their functions). Note, however, that &amp;quot;static&amp;quot; variables, even though they exist in globally accessible memory spaces, do not have public names and, hence, are not declared GLOBAL.&lt;br /&gt;
&lt;br /&gt;
Addressing of these variables is by name, thus, they have memory labels:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; int a&lt;br /&gt;
BSS             ; select segment for uninitialized variables&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
GLOBAL a, OBJ   ; declare a global symbol (linker)&lt;br /&gt;
LABEL  a        ; define the label&lt;br /&gt;
SALLOC 4          ; allocate space (sizeof(int) == 4)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; int a = 3&lt;br /&gt;
DATA            ; select segment for initialized variables&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
GLOBAL a, OBJ   ; declare a global symbol (linker)&lt;br /&gt;
LABEL  a        ; define the label&lt;br /&gt;
SINT 3         ; allocate space by defining initial value&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; const int a = 3&lt;br /&gt;
RODATA          ; select segment for constant objects&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
GLOBAL a, OBJ   ; declare a global symbol (linker)&lt;br /&gt;
LABEL  a        ; define the label&lt;br /&gt;
SINT 3         ; allocate space by defining initial value&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; char *s = &amp;quot;abcdef&amp;quot;&lt;br /&gt;
RODATA          ; select segment for constant objects (string literal)&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
LABEL  _L123    ; define the label&lt;br /&gt;
SSTRING &amp;quot;abcdef&amp;quot;    ; allocate space by defining initial value (string literal)&lt;br /&gt;
DATA            ; select segment for initialized variables&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
GLOBAL s, OBJ   ; declare a global symbol (linker)&lt;br /&gt;
LABEL  s        ; define the label&lt;br /&gt;
SADDR _L123        ; allocate space by defining initial value (address of literal)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; L22 example&lt;br /&gt;
;; var f = (int i) -&amp;gt; int:&lt;br /&gt;
;;    return i&lt;br /&gt;
TEXT _F123          ; select segment for this (anonymous) function&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
LABEL  _F123    ; define the label&lt;br /&gt;
ENTER 0&lt;br /&gt;
LOCAL +8 ; &amp;amp;i&lt;br /&gt;
LDINT ; i&lt;br /&gt;
STFVAL32&lt;br /&gt;
LEAVE &lt;br /&gt;
RET&lt;br /&gt;
DATA            ; select segment for initialized variables&lt;br /&gt;
ALIGN           ; align memory&lt;br /&gt;
GLOBAL f, OBJ   ; declare a global symbol (linker)&lt;br /&gt;
LABEL  f        ; define the label&lt;br /&gt;
SADDR _F123        ; allocate space by defining initial value (address of function)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Accessing global (permanent) variables ===&lt;br /&gt;
&lt;br /&gt;
We include in this category C-like &amp;quot;static&amp;quot; function variables (the only difference is that they are not accessed with their explicit names, but rather with a automatic symbol table-based name).&lt;br /&gt;
&lt;br /&gt;
Addressing of these variables is by name, as shown in the following examples.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = 1&lt;br /&gt;
INT 1    ; put 1 on the stack&lt;br /&gt;
DUP32      ; duplicate value&lt;br /&gt;
ADDR a   ; put address of &amp;quot;a&amp;quot; on the stack&lt;br /&gt;
STINT    ; write the value on the given address&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the resulting value is not needed, throw it away:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = 1;  // expression as instruction&lt;br /&gt;
INT 1    ; put 1 on the stack&lt;br /&gt;
DUP32      ; duplicate value&lt;br /&gt;
ADDR a   ; put address of &amp;quot;a&amp;quot; on the stack&lt;br /&gt;
STINT    ; write the value on the given address&lt;br /&gt;
TRASH 4&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = b (both global)&lt;br /&gt;
ADDR b   ; put address of &amp;quot;b&amp;quot; on the stack&lt;br /&gt;
LDINT     ; read the value at the given address&lt;br /&gt;
DUP32      ; duplicate value (= is an expression)&lt;br /&gt;
ADDR a   ; put address of &amp;quot;a&amp;quot; on the stack&lt;br /&gt;
STINT    ; write the value on the given address&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ADDR is immediately followed by LDINT, then the two instructions may be replaced by a single one with the same effect: ADDRV. Similarly, ADDR+STINT = ADDRA. Note that this, in most cases, will correspond to an optimization and its use by the code generator will be impossible or very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = 1&lt;br /&gt;
INT 1     ; put 1 on the stack&lt;br /&gt;
DUP32       ; duplicate value (= is an expression)&lt;br /&gt;
ADDRA a ; write the value in the address corresponding to &amp;quot;a&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = b (both global)&lt;br /&gt;
ADDRV b ; read value in the address of &amp;quot;b&amp;quot; and put it on the stack&lt;br /&gt;
DUP32       ; duplicate value (= is an expression)&lt;br /&gt;
ADDRA a ; write the value in the address corresponding to &amp;quot;a&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Accessing local variables ===&lt;br /&gt;
&lt;br /&gt;
In the following examples, we assume that both &#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are local variables (thus having negative offsets relative to the framepointer). If they were function arguments, the offsets would be positive.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = 1&lt;br /&gt;
INT 1    ; put 1 on the stack&lt;br /&gt;
DUP32       ; duplicate value (= is an expression)&lt;br /&gt;
LOCAL -4 ; put address of &amp;quot;a&amp;quot; (assuming offset -4) on the stack&lt;br /&gt;
STINT    ; write the value on the given address&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = b (both local)&lt;br /&gt;
LOCAL -8 ; put address of &amp;quot;b&amp;quot; (assuming offset -8) on the stack&lt;br /&gt;
LDINT     ; read the value at the given address&lt;br /&gt;
DUP32       ; duplicate value (= is an expression)&lt;br /&gt;
LOCAL -4 ; put address of &amp;quot;a&amp;quot; (assuming offset -4) on the stack&lt;br /&gt;
STINT    ; write the value on the given address&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If LOCAL is immediately followed by LDINT, then the two instructions may be replaced by a single one with the same effect: LOCV. Similarly, LOCAL+STINT = LOCA. Note that this, in most cases, will correspond to an optimization and its use by the code generator will be impossible or very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = 1&lt;br /&gt;
INT 1   ; put 1 on the stack&lt;br /&gt;
DUP32       ; duplicate value (= is an expression)&lt;br /&gt;
LOCA -4 ; write the value on the address of &amp;quot;a&amp;quot; (assuming offset -4)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
;; a = b (both local)&lt;br /&gt;
LOCV -8 ; read value in the address of &amp;quot;b&amp;quot; (assuming offset -8) and put it on the stack&lt;br /&gt;
DUP32       ; duplicate value (= is an expression)&lt;br /&gt;
LOCA -4 ; write the value on the address of &amp;quot;a&amp;quot; (assuming offset -4)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&lt;br /&gt;
* [[Code Generation/Example 1|Example 1]] - translating a C function to Postfix&lt;br /&gt;
* [[Code Generation/Example 2|Example 2]] - simple program printing a global string&lt;br /&gt;
* [[Code Generation/Example 3|Example 3]] - C function with pointer arithmetic to Postfix&lt;br /&gt;
* [[Code Generation/Example 4|Example 4]] - C while cycle&lt;br /&gt;
* [[Code Generation/Duplication of Floating Point Numbers on the Stack|Duplication of Floating Point Numbers on the Stack]] - this is a simple pure-Postfix example to illustrate duplication of stack values for double-precision floating point numbers.&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Code Generation/Exercise 5|Exercise 5]] - &amp;quot;gcd&amp;quot;&lt;br /&gt;
* [[Code Generation/Exercise 6|Exercise 6]] - &amp;quot;powmod&amp;quot;&lt;br /&gt;
* [[Code Generation/Exercise 7|Exercise 7]] - &amp;quot;traverse&amp;quot;&lt;br /&gt;
* [[Code Generation/Exercise 8|Exercise 8]] - set of small exercises and questions&lt;br /&gt;
* [[Code Generation/Exercise 9|Exercise 9]] - &amp;quot;mkvec&amp;quot; and &amp;quot;compute&amp;quot;, Test 2, 2012/06/06&lt;br /&gt;
* [[Code Generation/Exercise 10|Exercise 10]] - &amp;quot;forall&amp;quot; (version 1), Test 2, 2015/06/29&lt;br /&gt;
* [[Code Generation/Exercise 11|Exercise 11]] - &amp;quot;forall&amp;quot; (version 2), Test 2, 2015/06/29&lt;br /&gt;
* [[Code Generation/Exercise 12|Exercise 12]] - finding elements in vector, Test 2, 2016/06/17&lt;br /&gt;
* [[Code Generation/Exercise 13|Exercise 13]] - &#039;&#039;&#039;repeat&#039;&#039;&#039;&lt;br /&gt;
* [[Code Generation/Exercise 14|Exercise 14]] - &#039;&#039;&#039;mop&#039;&#039;&#039;&lt;br /&gt;
* [[Code Generation/Exercise 15|Exercise 15]] - &#039;&#039;&#039;gcd&#039;&#039;&#039; (take 2)&lt;br /&gt;
* [[Code Generation/Exercise 16|Exercise 16]] - &#039;&#039;&#039;heapSort&#039;&#039;&#039;, etc.&lt;br /&gt;
* [[Code Generation/Exercise 17|Exercise 17]] - &#039;&#039;&#039;find&#039;&#039;&#039;&lt;br /&gt;
* [[Code Generation/Exercise 18|Exercise 18]] - fragmentos com variações&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17787</id>
		<title>Postfix Reference Guide</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17787"/>
		<updated>2026-05-18T13:58:46Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Comparison operators for real numbers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
The Postfix reference guide contains information about the structure and operations of the stack machine.&lt;br /&gt;
&lt;br /&gt;
The original stack machine was created by Santos (2004). Is was composed by a set of macros to be used with printf functions. Each macro would “take” as arguments, either a number or a string. This was a simple and effective approach but was limited in its expressiveness.&lt;br /&gt;
&lt;br /&gt;
The current postﬁx code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it deﬁnes an interface to be used by semantic analysers, as deﬁned by a strategy pattern (Gamma et al., 1995). Speciﬁc implementations provide the realization of the postﬁx commands for a particular target machine. Since it is written in C++, it&#039;s very easy to extend to new needs and implementations (new target machines).&lt;br /&gt;
&lt;br /&gt;
Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name &amp;quot;postfix&amp;quot;, and three registers.&lt;br /&gt;
# IP -- the instruction pointer -- indicates the position of the next instruction to be executed;&lt;br /&gt;
# SP -- the stack pointer -- indicates the position of the element currently at the stack top;&lt;br /&gt;
# FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed.&lt;br /&gt;
&lt;br /&gt;
In the following tables, the &amp;quot;stack&amp;quot; columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation &#039;&#039;&#039;#length&#039;&#039;&#039; represents a set of &#039;&#039;length&#039;&#039; consecutive bytes in the stack, i.e., a vector.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OPERATION&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack before&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack after&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Description of actions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Consider the following fictitious example:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FAKE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a #8 b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | This is a fake operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this example, before the FAKE operation, the stack had at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by eight bytes, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. After executing the FAKE operation (which used those elements in some way), the stack has at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. The symbol &#039;&#039;&#039;$&#039;&#039;&#039; is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty).&lt;br /&gt;
&lt;br /&gt;
The following groups of operations are available in the Postfix interface:&lt;br /&gt;
&lt;br /&gt;
== Segments, Values, and Labels ==&lt;br /&gt;
&lt;br /&gt;
=== Segment selection ===&lt;br /&gt;
&lt;br /&gt;
These operations select various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSS&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for uninitialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RODATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized constant values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment (default)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;name&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT number&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;number&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Values (declaration in segments) ===&lt;br /&gt;
&lt;br /&gt;
These operations declare values directly in various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SALLOC size&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares an uninitialized vector with length &#039;&#039;&#039;size&#039;&#039;&#039; (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSHORT value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 16-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBYTE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 8-bit character &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SINT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 32-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static balanced ternary integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SFLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static simple precision (32-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SDOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static double precision (64-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SPOSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary posit real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary takum real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SADDR name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a name for an address (i.e., declares the address associated with &#039;&#039;&#039;name&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSTRING string&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static NULL-terminated character &#039;&#039;&#039;string&#039;&#039;&#039; (C-like) (may contain special characters)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Labels ===&lt;br /&gt;
&lt;br /&gt;
These operations handle symbols and their definitions within some segment. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALIGN&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Forces the alignment of code or data&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LABEL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a new label &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EXTERN name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares &#039;&#039;&#039;name&#039;&#039;&#039; as a symbol externally defined, i.e., defined in another compilation module&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GLOBAL name, type&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a &#039;&#039;&#039;name&#039;&#039;&#039; with a given &#039;&#039;&#039;type&#039;&#039;&#039; (see below) -- the declaration of a name must preceed its definition&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;!-- COMMON value || || || Declares that the name is common to other modules--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a declaration common to several modules, any number of modules may contain common or external declarations, but only one of them may contain an initialized declaration. A declaration does not need to be specified in a specific segment.&lt;br /&gt;
&lt;br /&gt;
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of &#039;&#039;&#039;GLOBAL&#039;&#039;&#039;.&lt;br /&gt;
* NONE - Unknown type&lt;br /&gt;
* FUNC - Name/label corresponds to a function&lt;br /&gt;
* OBJ - Name/label corresponds to an object (data)&lt;br /&gt;
&lt;br /&gt;
== Addressing, Loading and Storing ==&lt;br /&gt;
&lt;br /&gt;
Absolute addressing uses addresses based on named labels. Local addressing is used in function frames and uses offsets relative to the frame pointer to load data: negative addresses correspond to local variables, offset zero contains the previous (saved) value of the frame pointer, offset 4 (32 bits) contains the previous (saved) value of the instruction pointer, and, after offset 8, reside the function arguments.&lt;br /&gt;
&lt;br /&gt;
=== Adressing operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDR name &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ name &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load address of &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRA name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: store &#039;&#039;&#039;value&#039;&#039;&#039; to &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRV name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [name]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load value at &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCAL offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp+offset&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load address of &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCA offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: writes &#039;&#039;&#039;a&#039;&#039;&#039; to &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCV offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [fp+offset]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load value at &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions.&lt;br /&gt;
&lt;br /&gt;
=== Load operations ===&lt;br /&gt;
&lt;br /&gt;
The load instructions assume that the top of the stack contains an address pointing to the data to be read. Each load instruction will replace the address at the top of the stack with the contents of the position it points to. Load operations differ only in what they load.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDINT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBALANCED3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDPOSIT3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDTAKUM3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Store operations ===&lt;br /&gt;
&lt;br /&gt;
Store instructions assume the stack contains at the top the address where data is to be stored. That data is in the stack, immediately after the address. Store instructions differ only in what they store.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STINT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBALANCED3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STPOSIT3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STTAKUM3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Simple Stack Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 32-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 64-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 128-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary balanced integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a 4-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an 8-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, double precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | POSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ sp&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the value of the stack pointer&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 32-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 64-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 128-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALLOC&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Allocates in the stack an array with size &#039;&#039;&#039;bytes&#039;&#039;&#039;. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Arithmetic Operations ==&lt;br /&gt;
&lt;br /&gt;
The arithmetic operations considered here apply to both signed and unsigned integer arguments, and to double precision floating point arguments.&lt;br /&gt;
&lt;br /&gt;
=== Binary integer (32-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two natural (unsigned) integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UMOD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two natural (unsigned) integer values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary integer (64-bit/40-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BDIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Floating point (64-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take double precision floating point operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary posit (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary posit operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary takum (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary takum operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Increment and Decrement Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INCR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Adds &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]+delta&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DECR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtracts &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]-delta&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Type Conversion Operations ==&lt;br /&gt;
&lt;br /&gt;
The following instructions perform type conversions. The conversions are from and to integers (both binary and ternary) and real values (simple and double precision floating point, posit, and takum).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SRC2DST &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ src &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ dst &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Converts from source format (&#039;&#039;&#039;src&#039;&#039;&#039;) to destination format (&#039;&#039;&#039;dst&#039;&#039;&#039;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SRC&#039;&#039;&#039; and &#039;&#039;&#039;DST&#039;&#039;&#039; in the instuction above are as follows (not all combinations are available -- see the following table):&lt;br /&gt;
* &#039;&#039;&#039;B&#039;&#039;&#039;: Balanced ternary integer (64-bit/40-trit)&lt;br /&gt;
* &#039;&#039;&#039;D&#039;&#039;&#039;: Double precision floating point (64-bit)&lt;br /&gt;
* &#039;&#039;&#039;F&#039;&#039;&#039;: Single precision / simple precision floating point (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039;: Binary integer (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: Ternary posit (128-bit/80-trit)&lt;br /&gt;
* &#039;&#039;&#039;T&#039;&#039;&#039;: Ternary takum (128-bit/80-trit)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
|+ Instruction Opcodes (From Row \ To Column)&lt;br /&gt;
! !! B !! D !! F !! I !! P !! T&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| B2I &lt;br /&gt;
| B2P &lt;br /&gt;
| B2T&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| D2F &lt;br /&gt;
| D2I &lt;br /&gt;
| D2P &lt;br /&gt;
| D2T&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| F2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! I&lt;br /&gt;
| I2B &lt;br /&gt;
| I2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! P&lt;br /&gt;
| P2B &lt;br /&gt;
| P2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| P2T&lt;br /&gt;
|-&lt;br /&gt;
! T&lt;br /&gt;
| T2B &lt;br /&gt;
| T2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| T2P &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Comparison Operations ==&lt;br /&gt;
&lt;br /&gt;
=== Binary integer comparison instructions ===&lt;br /&gt;
&lt;br /&gt;
The comparison instructions are binary operations (each operand is a 32-bit binary integer) that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, &#039;&#039;&#039;false&#039;&#039;&#039; or &#039;&#039;&#039;true&#039;&#039;&#039; (32-bit binary integer). The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers (&amp;quot;flags&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EQ&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;equiv;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ne;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;not equal to&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following consider unsigned 32-bit binary integer operands (the result is also a 32-bit binary integer):&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039; for unsigned integers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Comparison operators for double precision binary floating point real numbers ===&lt;br /&gt;
&lt;br /&gt;
The DCMP operator compares two double precision binary floating point numbers (64 bits). The result is a 32-bit binary integer value: less than 0, if the first operand is lower than the second; 0, if they are equal; greater than 0, otherwise. &amp;lt;!--P3CMP (for ternary posits) and T3CMP (for ternary takums) work in a similar way. Note that posits and takums are natively compared using Kleene logic (the operators below translate that into Boolean logic).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DCMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b&lt;br /&gt;
&amp;lt;!--|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | P3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit posits; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | T3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit takums; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bitwise Operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take and 32-bit binary integer operands. The result is also a 32-bit binary integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise negation, i.e., one&#039;s complement&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | AND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise OR operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | XOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;oplus;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise XOR (exclusive OR) operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ternary Kleene logic operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take balanced ternary (64-bit/40-trit) integer operands. Note that these operators do not short-circuit Kleene logic with KAND/KOR. The result is also a balanced ternary (64-bit/40-trit) integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KNOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | NOT operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KAND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | OR operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rotation and Shift Operations ==&lt;br /&gt;
&lt;br /&gt;
Shift and rotation operations have as maximum value the number of bits of the underlying processor register (32 bits in a ix86-family processor). Safe operation for values above that limit is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rl&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rr&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;&amp;lt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRU &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRS &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (signed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Definition ==&lt;br /&gt;
&lt;br /&gt;
The following sections cover defining and calling functions.&lt;br /&gt;
&lt;br /&gt;
=== Starting a function ===&lt;br /&gt;
&lt;br /&gt;
Each function must allocate space for its local variables. This is done immediately after being called and before any other processing. The relevant operations are ENTER (to specify a given memory amount) and START (no space is reserved for local variables. Note that these operations do more than manipulate the stack: they also create an activation register for the function, i.e., they update the frame pointer and define a new stack frame.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ENTER bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp #bytes &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables (&#039;&#039;&#039;bytes&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | START &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Equivalent to &amp;quot;ENTER 0&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Leaving a function ===&lt;br /&gt;
&lt;br /&gt;
STFVAL32I/STFVAL32F or STFVAL64I/STFVAL64F must be called to specify return values in accordance with C conventions. Only return values that fit in the indicated registers need these operations. Other return values are passed by pointer.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 32-bit integer value from the stack (to eax)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 64-bit integer value from the stack (to eax:edx)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a single-precision (32-bit) floating point value from the stack (to st0)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a double-precision (64-bit) floating point value from the stack (to st0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that balanced-ternary numbers are represented by 64-bit binary numbers. Takums cannot be directly returned (they must be returned via pointer).&lt;br /&gt;
&lt;br /&gt;
The stack frame is destroyed by the LEAVE operation. This action must be performed immediately before returning control to the caller (with RET).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAVE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp ... &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
After the function&#039;s stack frame is destroyed and the activation register is restored to the caller, control must also be returned to the caller (i.e., IP must be updated).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RET&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function (the stack must contain the return address)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RETN bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes addr &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function and removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the caller&#039;s stack after removing the return address. This is more or less the same as &amp;quot;RET+TRASH bytes&amp;quot;. &#039;&#039;&#039;Note that this is not compatible with the Cdecl calling conventions.&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Calls ==&lt;br /&gt;
&lt;br /&gt;
In a stack machine the arguments for a function call are already in the stack. Thus, it is not necessary to put them there (it is enough not to remove them).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | CALL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Calls the &#039;&#039;&#039;name&#039;&#039;&#039;d function. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BRANCH &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Invokes a function at the &#039;&#039;&#039;address&#039;&#039;&#039; indicated at the top of the stack. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When building functions that conform to the C calling convention, the arguments are destroyed by the caller, &#039;&#039;after&#039;&#039; the return of the callee, using TRASH and stating the total size (i.e., for all arguments). &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TRASH bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To recover the returned value by the callee, and put it in the stack, the caller must call LDFVAL32I (32-bit integer value in eax) or LDFVAL32F (32-bit single-precision floating point value in st0). An analogous procedure is valid for LDFVAL64I (64-bit integer value in eax:edx) and LDFVAL64F (64-bit double-precision floating point value in st0).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax register to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax:edx registers to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (64 bits, double precision)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Basic Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JMP label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to &#039;&#039;&#039;label&#039;&#039;&#039; (does not affect or use the stack)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Conditional Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is 0 (zero)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is non-zero&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following operations combine comparisons and jumps.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JEQ label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;equiv;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ne;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLE label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following are for the unsigned versions of the comparisons.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b (unsigned)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NIL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | No action is performed&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a null operation (consumes time; does not change the processor&#039;s state)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17786</id>
		<title>Postfix Reference Guide</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17786"/>
		<updated>2026-05-18T13:57:13Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Simple Stack Operations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
The Postfix reference guide contains information about the structure and operations of the stack machine.&lt;br /&gt;
&lt;br /&gt;
The original stack machine was created by Santos (2004). Is was composed by a set of macros to be used with printf functions. Each macro would “take” as arguments, either a number or a string. This was a simple and effective approach but was limited in its expressiveness.&lt;br /&gt;
&lt;br /&gt;
The current postﬁx code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it deﬁnes an interface to be used by semantic analysers, as deﬁned by a strategy pattern (Gamma et al., 1995). Speciﬁc implementations provide the realization of the postﬁx commands for a particular target machine. Since it is written in C++, it&#039;s very easy to extend to new needs and implementations (new target machines).&lt;br /&gt;
&lt;br /&gt;
Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name &amp;quot;postfix&amp;quot;, and three registers.&lt;br /&gt;
# IP -- the instruction pointer -- indicates the position of the next instruction to be executed;&lt;br /&gt;
# SP -- the stack pointer -- indicates the position of the element currently at the stack top;&lt;br /&gt;
# FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed.&lt;br /&gt;
&lt;br /&gt;
In the following tables, the &amp;quot;stack&amp;quot; columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation &#039;&#039;&#039;#length&#039;&#039;&#039; represents a set of &#039;&#039;length&#039;&#039; consecutive bytes in the stack, i.e., a vector.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OPERATION&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack before&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack after&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Description of actions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Consider the following fictitious example:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FAKE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a #8 b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | This is a fake operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this example, before the FAKE operation, the stack had at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by eight bytes, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. After executing the FAKE operation (which used those elements in some way), the stack has at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. The symbol &#039;&#039;&#039;$&#039;&#039;&#039; is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty).&lt;br /&gt;
&lt;br /&gt;
The following groups of operations are available in the Postfix interface:&lt;br /&gt;
&lt;br /&gt;
== Segments, Values, and Labels ==&lt;br /&gt;
&lt;br /&gt;
=== Segment selection ===&lt;br /&gt;
&lt;br /&gt;
These operations select various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSS&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for uninitialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RODATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized constant values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment (default)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;name&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT number&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;number&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Values (declaration in segments) ===&lt;br /&gt;
&lt;br /&gt;
These operations declare values directly in various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SALLOC size&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares an uninitialized vector with length &#039;&#039;&#039;size&#039;&#039;&#039; (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSHORT value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 16-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBYTE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 8-bit character &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SINT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 32-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static balanced ternary integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SFLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static simple precision (32-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SDOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static double precision (64-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SPOSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary posit real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary takum real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SADDR name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a name for an address (i.e., declares the address associated with &#039;&#039;&#039;name&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSTRING string&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static NULL-terminated character &#039;&#039;&#039;string&#039;&#039;&#039; (C-like) (may contain special characters)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Labels ===&lt;br /&gt;
&lt;br /&gt;
These operations handle symbols and their definitions within some segment. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALIGN&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Forces the alignment of code or data&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LABEL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a new label &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EXTERN name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares &#039;&#039;&#039;name&#039;&#039;&#039; as a symbol externally defined, i.e., defined in another compilation module&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GLOBAL name, type&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a &#039;&#039;&#039;name&#039;&#039;&#039; with a given &#039;&#039;&#039;type&#039;&#039;&#039; (see below) -- the declaration of a name must preceed its definition&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;!-- COMMON value || || || Declares that the name is common to other modules--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a declaration common to several modules, any number of modules may contain common or external declarations, but only one of them may contain an initialized declaration. A declaration does not need to be specified in a specific segment.&lt;br /&gt;
&lt;br /&gt;
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of &#039;&#039;&#039;GLOBAL&#039;&#039;&#039;.&lt;br /&gt;
* NONE - Unknown type&lt;br /&gt;
* FUNC - Name/label corresponds to a function&lt;br /&gt;
* OBJ - Name/label corresponds to an object (data)&lt;br /&gt;
&lt;br /&gt;
== Addressing, Loading and Storing ==&lt;br /&gt;
&lt;br /&gt;
Absolute addressing uses addresses based on named labels. Local addressing is used in function frames and uses offsets relative to the frame pointer to load data: negative addresses correspond to local variables, offset zero contains the previous (saved) value of the frame pointer, offset 4 (32 bits) contains the previous (saved) value of the instruction pointer, and, after offset 8, reside the function arguments.&lt;br /&gt;
&lt;br /&gt;
=== Adressing operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDR name &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ name &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load address of &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRA name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: store &#039;&#039;&#039;value&#039;&#039;&#039; to &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRV name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [name]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load value at &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCAL offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp+offset&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load address of &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCA offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: writes &#039;&#039;&#039;a&#039;&#039;&#039; to &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCV offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [fp+offset]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load value at &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions.&lt;br /&gt;
&lt;br /&gt;
=== Load operations ===&lt;br /&gt;
&lt;br /&gt;
The load instructions assume that the top of the stack contains an address pointing to the data to be read. Each load instruction will replace the address at the top of the stack with the contents of the position it points to. Load operations differ only in what they load.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDINT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBALANCED3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDPOSIT3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDTAKUM3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Store operations ===&lt;br /&gt;
&lt;br /&gt;
Store instructions assume the stack contains at the top the address where data is to be stored. That data is in the stack, immediately after the address. Store instructions differ only in what they store.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STINT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBALANCED3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STPOSIT3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STTAKUM3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Simple Stack Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 32-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 64-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 128-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary balanced integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a 4-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an 8-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, double precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | POSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ sp&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the value of the stack pointer&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 32-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 64-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 128-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALLOC&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Allocates in the stack an array with size &#039;&#039;&#039;bytes&#039;&#039;&#039;. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Arithmetic Operations ==&lt;br /&gt;
&lt;br /&gt;
The arithmetic operations considered here apply to both signed and unsigned integer arguments, and to double precision floating point arguments.&lt;br /&gt;
&lt;br /&gt;
=== Binary integer (32-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two natural (unsigned) integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UMOD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two natural (unsigned) integer values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary integer (64-bit/40-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BDIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Floating point (64-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take double precision floating point operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary posit (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary posit operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary takum (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary takum operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Increment and Decrement Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INCR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Adds &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]+delta&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DECR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtracts &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]-delta&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Type Conversion Operations ==&lt;br /&gt;
&lt;br /&gt;
The following instructions perform type conversions. The conversions are from and to integers (both binary and ternary) and real values (simple and double precision floating point, posit, and takum).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SRC2DST &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ src &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ dst &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Converts from source format (&#039;&#039;&#039;src&#039;&#039;&#039;) to destination format (&#039;&#039;&#039;dst&#039;&#039;&#039;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SRC&#039;&#039;&#039; and &#039;&#039;&#039;DST&#039;&#039;&#039; in the instuction above are as follows (not all combinations are available -- see the following table):&lt;br /&gt;
* &#039;&#039;&#039;B&#039;&#039;&#039;: Balanced ternary integer (64-bit/40-trit)&lt;br /&gt;
* &#039;&#039;&#039;D&#039;&#039;&#039;: Double precision floating point (64-bit)&lt;br /&gt;
* &#039;&#039;&#039;F&#039;&#039;&#039;: Single precision / simple precision floating point (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039;: Binary integer (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: Ternary posit (128-bit/80-trit)&lt;br /&gt;
* &#039;&#039;&#039;T&#039;&#039;&#039;: Ternary takum (128-bit/80-trit)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
|+ Instruction Opcodes (From Row \ To Column)&lt;br /&gt;
! !! B !! D !! F !! I !! P !! T&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| B2I &lt;br /&gt;
| B2P &lt;br /&gt;
| B2T&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| D2F &lt;br /&gt;
| D2I &lt;br /&gt;
| D2P &lt;br /&gt;
| D2T&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| F2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! I&lt;br /&gt;
| I2B &lt;br /&gt;
| I2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! P&lt;br /&gt;
| P2B &lt;br /&gt;
| P2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| P2T&lt;br /&gt;
|-&lt;br /&gt;
! T&lt;br /&gt;
| T2B &lt;br /&gt;
| T2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| T2P &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Comparison Operations ==&lt;br /&gt;
&lt;br /&gt;
=== Binary integer comparison instructions ===&lt;br /&gt;
&lt;br /&gt;
The comparison instructions are binary operations (each operand is a 32-bit binary integer) that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, &#039;&#039;&#039;false&#039;&#039;&#039; or &#039;&#039;&#039;true&#039;&#039;&#039; (32-bit binary integer). The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers (&amp;quot;flags&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EQ&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;equiv;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ne;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;not equal to&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following consider unsigned 32-bit binary integer operands (the result is also a 32-bit binary integer):&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039; for unsigned integers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Comparison operators for real numbers ===&lt;br /&gt;
&lt;br /&gt;
The DCMP operator compares two double precision binary floating point numbers (64 bits). The result is a 32-bit binary integer value: less than 0, if the first operand is lower than the second; 0, if they are equal; greater than 0, otherwise. &amp;lt;!--P3CMP (for ternary posits) and T3CMP (for ternary takums) work in a similar way. Note that posits and takums are natively compared using Kleene logic (the operators below translate that into Boolean logic).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DCMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b&lt;br /&gt;
&amp;lt;!--|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | P3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit posits; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | T3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit takums; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bitwise Operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take and 32-bit binary integer operands. The result is also a 32-bit binary integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise negation, i.e., one&#039;s complement&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | AND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise OR operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | XOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;oplus;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise XOR (exclusive OR) operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ternary Kleene logic operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take balanced ternary (64-bit/40-trit) integer operands. Note that these operators do not short-circuit Kleene logic with KAND/KOR. The result is also a balanced ternary (64-bit/40-trit) integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KNOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | NOT operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KAND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | OR operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rotation and Shift Operations ==&lt;br /&gt;
&lt;br /&gt;
Shift and rotation operations have as maximum value the number of bits of the underlying processor register (32 bits in a ix86-family processor). Safe operation for values above that limit is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rl&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rr&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;&amp;lt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRU &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRS &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (signed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Definition ==&lt;br /&gt;
&lt;br /&gt;
The following sections cover defining and calling functions.&lt;br /&gt;
&lt;br /&gt;
=== Starting a function ===&lt;br /&gt;
&lt;br /&gt;
Each function must allocate space for its local variables. This is done immediately after being called and before any other processing. The relevant operations are ENTER (to specify a given memory amount) and START (no space is reserved for local variables. Note that these operations do more than manipulate the stack: they also create an activation register for the function, i.e., they update the frame pointer and define a new stack frame.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ENTER bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp #bytes &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables (&#039;&#039;&#039;bytes&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | START &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Equivalent to &amp;quot;ENTER 0&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Leaving a function ===&lt;br /&gt;
&lt;br /&gt;
STFVAL32I/STFVAL32F or STFVAL64I/STFVAL64F must be called to specify return values in accordance with C conventions. Only return values that fit in the indicated registers need these operations. Other return values are passed by pointer.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 32-bit integer value from the stack (to eax)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 64-bit integer value from the stack (to eax:edx)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a single-precision (32-bit) floating point value from the stack (to st0)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a double-precision (64-bit) floating point value from the stack (to st0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that balanced-ternary numbers are represented by 64-bit binary numbers. Takums cannot be directly returned (they must be returned via pointer).&lt;br /&gt;
&lt;br /&gt;
The stack frame is destroyed by the LEAVE operation. This action must be performed immediately before returning control to the caller (with RET).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAVE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp ... &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
After the function&#039;s stack frame is destroyed and the activation register is restored to the caller, control must also be returned to the caller (i.e., IP must be updated).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RET&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function (the stack must contain the return address)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RETN bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes addr &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function and removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the caller&#039;s stack after removing the return address. This is more or less the same as &amp;quot;RET+TRASH bytes&amp;quot;. &#039;&#039;&#039;Note that this is not compatible with the Cdecl calling conventions.&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Calls ==&lt;br /&gt;
&lt;br /&gt;
In a stack machine the arguments for a function call are already in the stack. Thus, it is not necessary to put them there (it is enough not to remove them).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | CALL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Calls the &#039;&#039;&#039;name&#039;&#039;&#039;d function. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BRANCH &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Invokes a function at the &#039;&#039;&#039;address&#039;&#039;&#039; indicated at the top of the stack. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When building functions that conform to the C calling convention, the arguments are destroyed by the caller, &#039;&#039;after&#039;&#039; the return of the callee, using TRASH and stating the total size (i.e., for all arguments). &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TRASH bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To recover the returned value by the callee, and put it in the stack, the caller must call LDFVAL32I (32-bit integer value in eax) or LDFVAL32F (32-bit single-precision floating point value in st0). An analogous procedure is valid for LDFVAL64I (64-bit integer value in eax:edx) and LDFVAL64F (64-bit double-precision floating point value in st0).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax register to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax:edx registers to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (64 bits, double precision)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Basic Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JMP label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to &#039;&#039;&#039;label&#039;&#039;&#039; (does not affect or use the stack)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Conditional Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is 0 (zero)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is non-zero&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following operations combine comparisons and jumps.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JEQ label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;equiv;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ne;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLE label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following are for the unsigned versions of the comparisons.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b (unsigned)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NIL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | No action is performed&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a null operation (consumes time; does not change the processor&#039;s state)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17785</id>
		<title>Postfix Reference Guide</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17785"/>
		<updated>2026-05-18T13:56:47Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Store operations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
The Postfix reference guide contains information about the structure and operations of the stack machine.&lt;br /&gt;
&lt;br /&gt;
The original stack machine was created by Santos (2004). Is was composed by a set of macros to be used with printf functions. Each macro would “take” as arguments, either a number or a string. This was a simple and effective approach but was limited in its expressiveness.&lt;br /&gt;
&lt;br /&gt;
The current postﬁx code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it deﬁnes an interface to be used by semantic analysers, as deﬁned by a strategy pattern (Gamma et al., 1995). Speciﬁc implementations provide the realization of the postﬁx commands for a particular target machine. Since it is written in C++, it&#039;s very easy to extend to new needs and implementations (new target machines).&lt;br /&gt;
&lt;br /&gt;
Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name &amp;quot;postfix&amp;quot;, and three registers.&lt;br /&gt;
# IP -- the instruction pointer -- indicates the position of the next instruction to be executed;&lt;br /&gt;
# SP -- the stack pointer -- indicates the position of the element currently at the stack top;&lt;br /&gt;
# FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed.&lt;br /&gt;
&lt;br /&gt;
In the following tables, the &amp;quot;stack&amp;quot; columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation &#039;&#039;&#039;#length&#039;&#039;&#039; represents a set of &#039;&#039;length&#039;&#039; consecutive bytes in the stack, i.e., a vector.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OPERATION&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack before&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack after&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Description of actions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Consider the following fictitious example:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FAKE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a #8 b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | This is a fake operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this example, before the FAKE operation, the stack had at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by eight bytes, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. After executing the FAKE operation (which used those elements in some way), the stack has at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. The symbol &#039;&#039;&#039;$&#039;&#039;&#039; is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty).&lt;br /&gt;
&lt;br /&gt;
The following groups of operations are available in the Postfix interface:&lt;br /&gt;
&lt;br /&gt;
== Segments, Values, and Labels ==&lt;br /&gt;
&lt;br /&gt;
=== Segment selection ===&lt;br /&gt;
&lt;br /&gt;
These operations select various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSS&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for uninitialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RODATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized constant values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment (default)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;name&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT number&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;number&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Values (declaration in segments) ===&lt;br /&gt;
&lt;br /&gt;
These operations declare values directly in various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SALLOC size&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares an uninitialized vector with length &#039;&#039;&#039;size&#039;&#039;&#039; (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSHORT value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 16-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBYTE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 8-bit character &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SINT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 32-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static balanced ternary integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SFLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static simple precision (32-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SDOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static double precision (64-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SPOSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary posit real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary takum real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SADDR name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a name for an address (i.e., declares the address associated with &#039;&#039;&#039;name&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSTRING string&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static NULL-terminated character &#039;&#039;&#039;string&#039;&#039;&#039; (C-like) (may contain special characters)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Labels ===&lt;br /&gt;
&lt;br /&gt;
These operations handle symbols and their definitions within some segment. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALIGN&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Forces the alignment of code or data&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LABEL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a new label &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EXTERN name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares &#039;&#039;&#039;name&#039;&#039;&#039; as a symbol externally defined, i.e., defined in another compilation module&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GLOBAL name, type&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a &#039;&#039;&#039;name&#039;&#039;&#039; with a given &#039;&#039;&#039;type&#039;&#039;&#039; (see below) -- the declaration of a name must preceed its definition&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;!-- COMMON value || || || Declares that the name is common to other modules--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a declaration common to several modules, any number of modules may contain common or external declarations, but only one of them may contain an initialized declaration. A declaration does not need to be specified in a specific segment.&lt;br /&gt;
&lt;br /&gt;
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of &#039;&#039;&#039;GLOBAL&#039;&#039;&#039;.&lt;br /&gt;
* NONE - Unknown type&lt;br /&gt;
* FUNC - Name/label corresponds to a function&lt;br /&gt;
* OBJ - Name/label corresponds to an object (data)&lt;br /&gt;
&lt;br /&gt;
== Addressing, Loading and Storing ==&lt;br /&gt;
&lt;br /&gt;
Absolute addressing uses addresses based on named labels. Local addressing is used in function frames and uses offsets relative to the frame pointer to load data: negative addresses correspond to local variables, offset zero contains the previous (saved) value of the frame pointer, offset 4 (32 bits) contains the previous (saved) value of the instruction pointer, and, after offset 8, reside the function arguments.&lt;br /&gt;
&lt;br /&gt;
=== Adressing operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDR name &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ name &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load address of &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRA name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: store &#039;&#039;&#039;value&#039;&#039;&#039; to &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRV name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [name]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load value at &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCAL offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp+offset&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load address of &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCA offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: writes &#039;&#039;&#039;a&#039;&#039;&#039; to &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCV offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [fp+offset]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load value at &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions.&lt;br /&gt;
&lt;br /&gt;
=== Load operations ===&lt;br /&gt;
&lt;br /&gt;
The load instructions assume that the top of the stack contains an address pointing to the data to be read. Each load instruction will replace the address at the top of the stack with the contents of the position it points to. Load operations differ only in what they load.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDINT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBALANCED3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDPOSIT3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDTAKUM3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Store operations ===&lt;br /&gt;
&lt;br /&gt;
Store instructions assume the stack contains at the top the address where data is to be stored. That data is in the stack, immediately after the address. Store instructions differ only in what they store.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STINT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBALANCED3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STPOSIT3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STTAKUM3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Simple Stack Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 32-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 64-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 128-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary balanced integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a 4-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an 8-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, double precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ sp&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the value of the stack pointer&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 32-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 64-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 128-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALLOC&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Allocates in the stack an array with size &#039;&#039;&#039;bytes&#039;&#039;&#039;. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Arithmetic Operations ==&lt;br /&gt;
&lt;br /&gt;
The arithmetic operations considered here apply to both signed and unsigned integer arguments, and to double precision floating point arguments.&lt;br /&gt;
&lt;br /&gt;
=== Binary integer (32-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two natural (unsigned) integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UMOD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two natural (unsigned) integer values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary integer (64-bit/40-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BDIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Floating point (64-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take double precision floating point operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary posit (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary posit operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary takum (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary takum operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Increment and Decrement Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INCR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Adds &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]+delta&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DECR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtracts &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]-delta&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Type Conversion Operations ==&lt;br /&gt;
&lt;br /&gt;
The following instructions perform type conversions. The conversions are from and to integers (both binary and ternary) and real values (simple and double precision floating point, posit, and takum).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SRC2DST &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ src &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ dst &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Converts from source format (&#039;&#039;&#039;src&#039;&#039;&#039;) to destination format (&#039;&#039;&#039;dst&#039;&#039;&#039;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SRC&#039;&#039;&#039; and &#039;&#039;&#039;DST&#039;&#039;&#039; in the instuction above are as follows (not all combinations are available -- see the following table):&lt;br /&gt;
* &#039;&#039;&#039;B&#039;&#039;&#039;: Balanced ternary integer (64-bit/40-trit)&lt;br /&gt;
* &#039;&#039;&#039;D&#039;&#039;&#039;: Double precision floating point (64-bit)&lt;br /&gt;
* &#039;&#039;&#039;F&#039;&#039;&#039;: Single precision / simple precision floating point (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039;: Binary integer (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: Ternary posit (128-bit/80-trit)&lt;br /&gt;
* &#039;&#039;&#039;T&#039;&#039;&#039;: Ternary takum (128-bit/80-trit)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
|+ Instruction Opcodes (From Row \ To Column)&lt;br /&gt;
! !! B !! D !! F !! I !! P !! T&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| B2I &lt;br /&gt;
| B2P &lt;br /&gt;
| B2T&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| D2F &lt;br /&gt;
| D2I &lt;br /&gt;
| D2P &lt;br /&gt;
| D2T&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| F2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! I&lt;br /&gt;
| I2B &lt;br /&gt;
| I2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! P&lt;br /&gt;
| P2B &lt;br /&gt;
| P2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| P2T&lt;br /&gt;
|-&lt;br /&gt;
! T&lt;br /&gt;
| T2B &lt;br /&gt;
| T2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| T2P &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Comparison Operations ==&lt;br /&gt;
&lt;br /&gt;
=== Binary integer comparison instructions ===&lt;br /&gt;
&lt;br /&gt;
The comparison instructions are binary operations (each operand is a 32-bit binary integer) that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, &#039;&#039;&#039;false&#039;&#039;&#039; or &#039;&#039;&#039;true&#039;&#039;&#039; (32-bit binary integer). The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers (&amp;quot;flags&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EQ&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;equiv;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ne;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;not equal to&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following consider unsigned 32-bit binary integer operands (the result is also a 32-bit binary integer):&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039; for unsigned integers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Comparison operators for real numbers ===&lt;br /&gt;
&lt;br /&gt;
The DCMP operator compares two double precision binary floating point numbers (64 bits). The result is a 32-bit binary integer value: less than 0, if the first operand is lower than the second; 0, if they are equal; greater than 0, otherwise. &amp;lt;!--P3CMP (for ternary posits) and T3CMP (for ternary takums) work in a similar way. Note that posits and takums are natively compared using Kleene logic (the operators below translate that into Boolean logic).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DCMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b&lt;br /&gt;
&amp;lt;!--|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | P3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit posits; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | T3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit takums; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bitwise Operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take and 32-bit binary integer operands. The result is also a 32-bit binary integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise negation, i.e., one&#039;s complement&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | AND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise OR operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | XOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;oplus;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise XOR (exclusive OR) operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ternary Kleene logic operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take balanced ternary (64-bit/40-trit) integer operands. Note that these operators do not short-circuit Kleene logic with KAND/KOR. The result is also a balanced ternary (64-bit/40-trit) integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KNOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | NOT operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KAND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | OR operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rotation and Shift Operations ==&lt;br /&gt;
&lt;br /&gt;
Shift and rotation operations have as maximum value the number of bits of the underlying processor register (32 bits in a ix86-family processor). Safe operation for values above that limit is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rl&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rr&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;&amp;lt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRU &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRS &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (signed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Definition ==&lt;br /&gt;
&lt;br /&gt;
The following sections cover defining and calling functions.&lt;br /&gt;
&lt;br /&gt;
=== Starting a function ===&lt;br /&gt;
&lt;br /&gt;
Each function must allocate space for its local variables. This is done immediately after being called and before any other processing. The relevant operations are ENTER (to specify a given memory amount) and START (no space is reserved for local variables. Note that these operations do more than manipulate the stack: they also create an activation register for the function, i.e., they update the frame pointer and define a new stack frame.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ENTER bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp #bytes &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables (&#039;&#039;&#039;bytes&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | START &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Equivalent to &amp;quot;ENTER 0&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Leaving a function ===&lt;br /&gt;
&lt;br /&gt;
STFVAL32I/STFVAL32F or STFVAL64I/STFVAL64F must be called to specify return values in accordance with C conventions. Only return values that fit in the indicated registers need these operations. Other return values are passed by pointer.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 32-bit integer value from the stack (to eax)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 64-bit integer value from the stack (to eax:edx)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a single-precision (32-bit) floating point value from the stack (to st0)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a double-precision (64-bit) floating point value from the stack (to st0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that balanced-ternary numbers are represented by 64-bit binary numbers. Takums cannot be directly returned (they must be returned via pointer).&lt;br /&gt;
&lt;br /&gt;
The stack frame is destroyed by the LEAVE operation. This action must be performed immediately before returning control to the caller (with RET).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAVE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp ... &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
After the function&#039;s stack frame is destroyed and the activation register is restored to the caller, control must also be returned to the caller (i.e., IP must be updated).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RET&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function (the stack must contain the return address)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RETN bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes addr &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function and removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the caller&#039;s stack after removing the return address. This is more or less the same as &amp;quot;RET+TRASH bytes&amp;quot;. &#039;&#039;&#039;Note that this is not compatible with the Cdecl calling conventions.&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Calls ==&lt;br /&gt;
&lt;br /&gt;
In a stack machine the arguments for a function call are already in the stack. Thus, it is not necessary to put them there (it is enough not to remove them).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | CALL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Calls the &#039;&#039;&#039;name&#039;&#039;&#039;d function. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BRANCH &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Invokes a function at the &#039;&#039;&#039;address&#039;&#039;&#039; indicated at the top of the stack. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When building functions that conform to the C calling convention, the arguments are destroyed by the caller, &#039;&#039;after&#039;&#039; the return of the callee, using TRASH and stating the total size (i.e., for all arguments). &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TRASH bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To recover the returned value by the callee, and put it in the stack, the caller must call LDFVAL32I (32-bit integer value in eax) or LDFVAL32F (32-bit single-precision floating point value in st0). An analogous procedure is valid for LDFVAL64I (64-bit integer value in eax:edx) and LDFVAL64F (64-bit double-precision floating point value in st0).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax register to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax:edx registers to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (64 bits, double precision)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Basic Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JMP label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to &#039;&#039;&#039;label&#039;&#039;&#039; (does not affect or use the stack)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Conditional Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is 0 (zero)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is non-zero&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following operations combine comparisons and jumps.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JEQ label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;equiv;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ne;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLE label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following are for the unsigned versions of the comparisons.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b (unsigned)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NIL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | No action is performed&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a null operation (consumes time; does not change the processor&#039;s state)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17784</id>
		<title>Postfix Reference Guide</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17784"/>
		<updated>2026-05-18T13:56:26Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Load operations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
The Postfix reference guide contains information about the structure and operations of the stack machine.&lt;br /&gt;
&lt;br /&gt;
The original stack machine was created by Santos (2004). Is was composed by a set of macros to be used with printf functions. Each macro would “take” as arguments, either a number or a string. This was a simple and effective approach but was limited in its expressiveness.&lt;br /&gt;
&lt;br /&gt;
The current postﬁx code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it deﬁnes an interface to be used by semantic analysers, as deﬁned by a strategy pattern (Gamma et al., 1995). Speciﬁc implementations provide the realization of the postﬁx commands for a particular target machine. Since it is written in C++, it&#039;s very easy to extend to new needs and implementations (new target machines).&lt;br /&gt;
&lt;br /&gt;
Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name &amp;quot;postfix&amp;quot;, and three registers.&lt;br /&gt;
# IP -- the instruction pointer -- indicates the position of the next instruction to be executed;&lt;br /&gt;
# SP -- the stack pointer -- indicates the position of the element currently at the stack top;&lt;br /&gt;
# FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed.&lt;br /&gt;
&lt;br /&gt;
In the following tables, the &amp;quot;stack&amp;quot; columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation &#039;&#039;&#039;#length&#039;&#039;&#039; represents a set of &#039;&#039;length&#039;&#039; consecutive bytes in the stack, i.e., a vector.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OPERATION&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack before&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack after&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Description of actions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Consider the following fictitious example:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FAKE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a #8 b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | This is a fake operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this example, before the FAKE operation, the stack had at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by eight bytes, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. After executing the FAKE operation (which used those elements in some way), the stack has at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. The symbol &#039;&#039;&#039;$&#039;&#039;&#039; is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty).&lt;br /&gt;
&lt;br /&gt;
The following groups of operations are available in the Postfix interface:&lt;br /&gt;
&lt;br /&gt;
== Segments, Values, and Labels ==&lt;br /&gt;
&lt;br /&gt;
=== Segment selection ===&lt;br /&gt;
&lt;br /&gt;
These operations select various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSS&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for uninitialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RODATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized constant values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment (default)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;name&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT number&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;number&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Values (declaration in segments) ===&lt;br /&gt;
&lt;br /&gt;
These operations declare values directly in various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SALLOC size&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares an uninitialized vector with length &#039;&#039;&#039;size&#039;&#039;&#039; (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSHORT value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 16-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBYTE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 8-bit character &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SINT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 32-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static balanced ternary integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SFLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static simple precision (32-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SDOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static double precision (64-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SPOSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary posit real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary takum real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SADDR name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a name for an address (i.e., declares the address associated with &#039;&#039;&#039;name&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSTRING string&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static NULL-terminated character &#039;&#039;&#039;string&#039;&#039;&#039; (C-like) (may contain special characters)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Labels ===&lt;br /&gt;
&lt;br /&gt;
These operations handle symbols and their definitions within some segment. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALIGN&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Forces the alignment of code or data&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LABEL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a new label &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EXTERN name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares &#039;&#039;&#039;name&#039;&#039;&#039; as a symbol externally defined, i.e., defined in another compilation module&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GLOBAL name, type&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a &#039;&#039;&#039;name&#039;&#039;&#039; with a given &#039;&#039;&#039;type&#039;&#039;&#039; (see below) -- the declaration of a name must preceed its definition&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;!-- COMMON value || || || Declares that the name is common to other modules--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a declaration common to several modules, any number of modules may contain common or external declarations, but only one of them may contain an initialized declaration. A declaration does not need to be specified in a specific segment.&lt;br /&gt;
&lt;br /&gt;
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of &#039;&#039;&#039;GLOBAL&#039;&#039;&#039;.&lt;br /&gt;
* NONE - Unknown type&lt;br /&gt;
* FUNC - Name/label corresponds to a function&lt;br /&gt;
* OBJ - Name/label corresponds to an object (data)&lt;br /&gt;
&lt;br /&gt;
== Addressing, Loading and Storing ==&lt;br /&gt;
&lt;br /&gt;
Absolute addressing uses addresses based on named labels. Local addressing is used in function frames and uses offsets relative to the frame pointer to load data: negative addresses correspond to local variables, offset zero contains the previous (saved) value of the frame pointer, offset 4 (32 bits) contains the previous (saved) value of the instruction pointer, and, after offset 8, reside the function arguments.&lt;br /&gt;
&lt;br /&gt;
=== Adressing operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDR name &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ name &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load address of &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRA name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: store &#039;&#039;&#039;value&#039;&#039;&#039; to &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRV name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [name]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load value at &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCAL offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp+offset&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load address of &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCA offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: writes &#039;&#039;&#039;a&#039;&#039;&#039; to &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCV offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [fp+offset]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load value at &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions.&lt;br /&gt;
&lt;br /&gt;
=== Load operations ===&lt;br /&gt;
&lt;br /&gt;
The load instructions assume that the top of the stack contains an address pointing to the data to be read. Each load instruction will replace the address at the top of the stack with the contents of the position it points to. Load operations differ only in what they load.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDINT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBALANCED3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDPOSIT3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDTAKUM3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Store operations ===&lt;br /&gt;
&lt;br /&gt;
Store instructions assume the stack contains at the top the address where data is to be stored. That data is in the stack, immediately after the address. Store instructions differ only in what they store.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STINT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBALANCED3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STTAKUM3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Simple Stack Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 32-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 64-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 128-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary balanced integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a 4-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an 8-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, double precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ sp&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the value of the stack pointer&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 32-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 64-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 128-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALLOC&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Allocates in the stack an array with size &#039;&#039;&#039;bytes&#039;&#039;&#039;. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Arithmetic Operations ==&lt;br /&gt;
&lt;br /&gt;
The arithmetic operations considered here apply to both signed and unsigned integer arguments, and to double precision floating point arguments.&lt;br /&gt;
&lt;br /&gt;
=== Binary integer (32-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two natural (unsigned) integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UMOD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two natural (unsigned) integer values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary integer (64-bit/40-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BDIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Floating point (64-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take double precision floating point operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary posit (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary posit operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary takum (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary takum operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Increment and Decrement Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INCR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Adds &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]+delta&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DECR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtracts &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]-delta&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Type Conversion Operations ==&lt;br /&gt;
&lt;br /&gt;
The following instructions perform type conversions. The conversions are from and to integers (both binary and ternary) and real values (simple and double precision floating point, posit, and takum).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SRC2DST &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ src &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ dst &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Converts from source format (&#039;&#039;&#039;src&#039;&#039;&#039;) to destination format (&#039;&#039;&#039;dst&#039;&#039;&#039;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SRC&#039;&#039;&#039; and &#039;&#039;&#039;DST&#039;&#039;&#039; in the instuction above are as follows (not all combinations are available -- see the following table):&lt;br /&gt;
* &#039;&#039;&#039;B&#039;&#039;&#039;: Balanced ternary integer (64-bit/40-trit)&lt;br /&gt;
* &#039;&#039;&#039;D&#039;&#039;&#039;: Double precision floating point (64-bit)&lt;br /&gt;
* &#039;&#039;&#039;F&#039;&#039;&#039;: Single precision / simple precision floating point (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039;: Binary integer (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: Ternary posit (128-bit/80-trit)&lt;br /&gt;
* &#039;&#039;&#039;T&#039;&#039;&#039;: Ternary takum (128-bit/80-trit)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
|+ Instruction Opcodes (From Row \ To Column)&lt;br /&gt;
! !! B !! D !! F !! I !! P !! T&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| B2I &lt;br /&gt;
| B2P &lt;br /&gt;
| B2T&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| D2F &lt;br /&gt;
| D2I &lt;br /&gt;
| D2P &lt;br /&gt;
| D2T&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| F2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! I&lt;br /&gt;
| I2B &lt;br /&gt;
| I2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! P&lt;br /&gt;
| P2B &lt;br /&gt;
| P2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| P2T&lt;br /&gt;
|-&lt;br /&gt;
! T&lt;br /&gt;
| T2B &lt;br /&gt;
| T2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| T2P &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Comparison Operations ==&lt;br /&gt;
&lt;br /&gt;
=== Binary integer comparison instructions ===&lt;br /&gt;
&lt;br /&gt;
The comparison instructions are binary operations (each operand is a 32-bit binary integer) that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, &#039;&#039;&#039;false&#039;&#039;&#039; or &#039;&#039;&#039;true&#039;&#039;&#039; (32-bit binary integer). The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers (&amp;quot;flags&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EQ&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;equiv;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ne;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;not equal to&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following consider unsigned 32-bit binary integer operands (the result is also a 32-bit binary integer):&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039; for unsigned integers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Comparison operators for real numbers ===&lt;br /&gt;
&lt;br /&gt;
The DCMP operator compares two double precision binary floating point numbers (64 bits). The result is a 32-bit binary integer value: less than 0, if the first operand is lower than the second; 0, if they are equal; greater than 0, otherwise. &amp;lt;!--P3CMP (for ternary posits) and T3CMP (for ternary takums) work in a similar way. Note that posits and takums are natively compared using Kleene logic (the operators below translate that into Boolean logic).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DCMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b&lt;br /&gt;
&amp;lt;!--|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | P3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit posits; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | T3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit takums; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bitwise Operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take and 32-bit binary integer operands. The result is also a 32-bit binary integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise negation, i.e., one&#039;s complement&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | AND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise OR operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | XOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;oplus;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise XOR (exclusive OR) operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ternary Kleene logic operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take balanced ternary (64-bit/40-trit) integer operands. Note that these operators do not short-circuit Kleene logic with KAND/KOR. The result is also a balanced ternary (64-bit/40-trit) integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KNOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | NOT operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KAND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | OR operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rotation and Shift Operations ==&lt;br /&gt;
&lt;br /&gt;
Shift and rotation operations have as maximum value the number of bits of the underlying processor register (32 bits in a ix86-family processor). Safe operation for values above that limit is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rl&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rr&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;&amp;lt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRU &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRS &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (signed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Definition ==&lt;br /&gt;
&lt;br /&gt;
The following sections cover defining and calling functions.&lt;br /&gt;
&lt;br /&gt;
=== Starting a function ===&lt;br /&gt;
&lt;br /&gt;
Each function must allocate space for its local variables. This is done immediately after being called and before any other processing. The relevant operations are ENTER (to specify a given memory amount) and START (no space is reserved for local variables. Note that these operations do more than manipulate the stack: they also create an activation register for the function, i.e., they update the frame pointer and define a new stack frame.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ENTER bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp #bytes &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables (&#039;&#039;&#039;bytes&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | START &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Equivalent to &amp;quot;ENTER 0&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Leaving a function ===&lt;br /&gt;
&lt;br /&gt;
STFVAL32I/STFVAL32F or STFVAL64I/STFVAL64F must be called to specify return values in accordance with C conventions. Only return values that fit in the indicated registers need these operations. Other return values are passed by pointer.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 32-bit integer value from the stack (to eax)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 64-bit integer value from the stack (to eax:edx)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a single-precision (32-bit) floating point value from the stack (to st0)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a double-precision (64-bit) floating point value from the stack (to st0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that balanced-ternary numbers are represented by 64-bit binary numbers. Takums cannot be directly returned (they must be returned via pointer).&lt;br /&gt;
&lt;br /&gt;
The stack frame is destroyed by the LEAVE operation. This action must be performed immediately before returning control to the caller (with RET).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAVE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp ... &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
After the function&#039;s stack frame is destroyed and the activation register is restored to the caller, control must also be returned to the caller (i.e., IP must be updated).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RET&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function (the stack must contain the return address)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RETN bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes addr &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function and removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the caller&#039;s stack after removing the return address. This is more or less the same as &amp;quot;RET+TRASH bytes&amp;quot;. &#039;&#039;&#039;Note that this is not compatible with the Cdecl calling conventions.&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Calls ==&lt;br /&gt;
&lt;br /&gt;
In a stack machine the arguments for a function call are already in the stack. Thus, it is not necessary to put them there (it is enough not to remove them).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | CALL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Calls the &#039;&#039;&#039;name&#039;&#039;&#039;d function. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BRANCH &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Invokes a function at the &#039;&#039;&#039;address&#039;&#039;&#039; indicated at the top of the stack. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When building functions that conform to the C calling convention, the arguments are destroyed by the caller, &#039;&#039;after&#039;&#039; the return of the callee, using TRASH and stating the total size (i.e., for all arguments). &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TRASH bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To recover the returned value by the callee, and put it in the stack, the caller must call LDFVAL32I (32-bit integer value in eax) or LDFVAL32F (32-bit single-precision floating point value in st0). An analogous procedure is valid for LDFVAL64I (64-bit integer value in eax:edx) and LDFVAL64F (64-bit double-precision floating point value in st0).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax register to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax:edx registers to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (64 bits, double precision)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Basic Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JMP label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to &#039;&#039;&#039;label&#039;&#039;&#039; (does not affect or use the stack)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Conditional Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is 0 (zero)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is non-zero&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following operations combine comparisons and jumps.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JEQ label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;equiv;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ne;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLE label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following are for the unsigned versions of the comparisons.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b (unsigned)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NIL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | No action is performed&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a null operation (consumes time; does not change the processor&#039;s state)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17783</id>
		<title>Postfix Reference Guide</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Postfix_Reference_Guide&amp;diff=17783"/>
		<updated>2026-05-18T13:55:55Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Values (declaration in segments) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
The Postfix reference guide contains information about the structure and operations of the stack machine.&lt;br /&gt;
&lt;br /&gt;
The original stack machine was created by Santos (2004). Is was composed by a set of macros to be used with printf functions. Each macro would “take” as arguments, either a number or a string. This was a simple and effective approach but was limited in its expressiveness.&lt;br /&gt;
&lt;br /&gt;
The current postﬁx code generator class maintains the stack machine abstraction, but does not rely on macros. Instead, it deﬁnes an interface to be used by semantic analysers, as deﬁned by a strategy pattern (Gamma et al., 1995). Speciﬁc implementations provide the realization of the postﬁx commands for a particular target machine. Since it is written in C++, it&#039;s very easy to extend to new needs and implementations (new target machines).&lt;br /&gt;
&lt;br /&gt;
Like the original postfix code generator, the current abstraction uses an architecture based on a stack machine, hence the name &amp;quot;postfix&amp;quot;, and three registers.&lt;br /&gt;
# IP -- the instruction pointer -- indicates the position of the next instruction to be executed;&lt;br /&gt;
# SP -- the stack pointer -- indicates the position of the element currently at the stack top;&lt;br /&gt;
# FP -- the frame pointer -- indicates the position of the activation register of the function currently being executed.&lt;br /&gt;
&lt;br /&gt;
In the following tables, the &amp;quot;stack&amp;quot; columns present the results of the actions on the values at the top of the stack. Note that only elements relevant in a given context, i.e., that of the postfix instruction being executed, are shown. The notation &#039;&#039;&#039;#length&#039;&#039;&#039; represents a set of &#039;&#039;length&#039;&#039; consecutive bytes in the stack, i.e., a vector.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OPERATION&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack before&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | stack after&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Description of actions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Consider the following fictitious example:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FAKE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a #8 b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | This is a fake operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In this example, before the FAKE operation, the stack had at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by eight bytes, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. After executing the FAKE operation (which used those elements in some way), the stack has at its top &#039;&#039;&#039;b&#039;&#039;&#039;, followed by &#039;&#039;&#039;a&#039;&#039;&#039;. The symbol &#039;&#039;&#039;$&#039;&#039;&#039; is used to denote the point in the stack not affected by the current operation (this could be the top if the stack were empty).&lt;br /&gt;
&lt;br /&gt;
The following groups of operations are available in the Postfix interface:&lt;br /&gt;
&lt;br /&gt;
== Segments, Values, and Labels ==&lt;br /&gt;
&lt;br /&gt;
=== Segment selection ===&lt;br /&gt;
&lt;br /&gt;
These operations select various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSS&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for uninitialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RODATA&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the data segment for initialized constant values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment (default)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;name&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TEXT number&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Specifies/selects the text (code) segment with name &#039;&#039;number&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Values (declaration in segments) ===&lt;br /&gt;
&lt;br /&gt;
These operations declare values directly in various segments. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SALLOC size&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares an uninitialized vector with length &#039;&#039;&#039;size&#039;&#039;&#039; (in bytes)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSHORT value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 16-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBYTE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 8-bit character &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SINT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static 32-bit integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SBALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static balanced ternary integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SFLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static simple precision (32-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SDOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static double precision (64-bit) floating point &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SPOSIT3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary posit real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static ternary takum real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SADDR name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a name for an address (i.e., declares the address associated with &#039;&#039;&#039;name&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SSTRING string&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a static NULL-terminated character &#039;&#039;&#039;string&#039;&#039;&#039; (C-like) (may contain special characters)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Labels ===&lt;br /&gt;
&lt;br /&gt;
These operations handle symbols and their definitions within some segment. They do not affect the stack.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALIGN&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Forces the alignment of code or data&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LABEL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a new label &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EXTERN name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares &#039;&#039;&#039;name&#039;&#039;&#039; as a symbol externally defined, i.e., defined in another compilation module&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GLOBAL name, type&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Declares a &#039;&#039;&#039;name&#039;&#039;&#039; with a given &#039;&#039;&#039;type&#039;&#039;&#039; (see below) -- the declaration of a name must preceed its definition&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;!-- COMMON value || || || Declares that the name is common to other modules--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a declaration common to several modules, any number of modules may contain common or external declarations, but only one of them may contain an initialized declaration. A declaration does not need to be specified in a specific segment.&lt;br /&gt;
&lt;br /&gt;
Global names may be of different types. These labels are to be used to generate the types needed for the second argument of &#039;&#039;&#039;GLOBAL&#039;&#039;&#039;.&lt;br /&gt;
* NONE - Unknown type&lt;br /&gt;
* FUNC - Name/label corresponds to a function&lt;br /&gt;
* OBJ - Name/label corresponds to an object (data)&lt;br /&gt;
&lt;br /&gt;
== Addressing, Loading and Storing ==&lt;br /&gt;
&lt;br /&gt;
Absolute addressing uses addresses based on named labels. Local addressing is used in function frames and uses offsets relative to the frame pointer to load data: negative addresses correspond to local variables, offset zero contains the previous (saved) value of the frame pointer, offset 4 (32 bits) contains the previous (saved) value of the instruction pointer, and, after offset 8, reside the function arguments.&lt;br /&gt;
&lt;br /&gt;
=== Adressing operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDR name &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ name &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load address of &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRA name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: store &#039;&#039;&#039;value&#039;&#039;&#039; to &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADDRV name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [name]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Absolute addressing: load value at &#039;&#039;&#039;name&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCAL offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp+offset&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load address of &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCA offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: writes &#039;&#039;&#039;a&#039;&#039;&#039; to &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LOCV offset&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [fp+offset]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Local addressing: load value at &#039;&#039;&#039;offset&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
ADDRA, ADDRV, LOCA, LOCV are functionally equivalent to ADDR+STINT, ADDR+LDINT, LOCAL+STINT, LOCAL+LDINT, but the generated code is more efficient. They are compound operations (i.e., they contain not only the addressing part, but also the load/store part as well). Note that the postfix_writer visitor is, in general, incapable of generating these instructions.&lt;br /&gt;
&lt;br /&gt;
=== Load operations ===&lt;br /&gt;
&lt;br /&gt;
The load instructions assume that the top of the stack contains an address pointing to the data to be read. Each load instruction will replace the address at the top of the stack with the contents of the position it points to. Load operations differ only in what they load.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDINT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDBALANCED3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDTAKUM3&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ [addr]&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Loads 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Store operations ===&lt;br /&gt;
&lt;br /&gt;
Store instructions assume the stack contains at the top the address where data is to be stored. That data is in the stack, immediately after the address. Store instructions differ only in what they store.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBYTE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 1 byte (char)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STSHORT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 2 bytes (short)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STINT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (int)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STBALANCED3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (40-trit balanced ternary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFLOAT&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 4 bytes (float)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STDOUBLE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 8 bytes (double)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STTAKUM3 &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ val addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Stores 16 bytes (80-trit ternary real)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Simple Stack Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 32-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 64-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DUP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a a&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Duplicates the 128-bit value at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an integer &#039;&#039;&#039;value&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BALANCED3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary balanced integer &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, 40 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | FLOAT value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a 4-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DOUBLE value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes an 8-byte float &#039;&#039;&#039;value&#039;&#039;&#039; (64 bits, double precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TAKUM3 value&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes a ternary real &#039;&#039;&#039;value&#039;&#039;&#039; (128 bits, 80 trits)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ sp&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the value of the stack pointer&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP32&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 32-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP64&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 64-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SWAP128&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ b a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Swaps the two 128-bit values at the top of the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ALLOC&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Allocates in the stack an array with size &#039;&#039;&#039;bytes&#039;&#039;&#039;. Since this operation alters the meaning of offsets in the stack, care should be taken when local variables exist.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Arithmetic Operations ==&lt;br /&gt;
&lt;br /&gt;
The arithmetic operations considered here apply to both signed and unsigned integer arguments, and to double precision floating point arguments.&lt;br /&gt;
&lt;br /&gt;
=== Binary integer (32-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | MOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two natural (unsigned) integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UMOD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two natural (unsigned) integer values.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary integer (64-bit/40-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric) of integer value&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer sum of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer subtraction of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMUL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer multiplication of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BDIV &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Integer division of two integer values&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BMOD&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a%b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Remainder of the integer division of two integer values&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Floating point (64-bit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take double precision floating point operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary posit (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary posit operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | PDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Ternary takum (128-bit/80-trit) operations ===&lt;br /&gt;
&lt;br /&gt;
These operations take ternary takum operands.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TNEG &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ -a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Negation (symmetric)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TADD &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a+b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Sum&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TSUB&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a-b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtraction&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TMUL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a*b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Multiplication&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TDIV&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a/b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Division&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Increment and Decrement Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | INCR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Adds &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]+delta&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DECR delta&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Subtracts &#039;&#039;&#039;delta&#039;&#039;&#039; to the binary integer value at the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack, i.e. &#039;&#039;[address]&#039;&#039; becomes &#039;&#039;[address]-delta&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Type Conversion Operations ==&lt;br /&gt;
&lt;br /&gt;
The following instructions perform type conversions. The conversions are from and to integers (both binary and ternary) and real values (simple and double precision floating point, posit, and takum).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SRC2DST &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ src &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ dst &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Converts from source format (&#039;&#039;&#039;src&#039;&#039;&#039;) to destination format (&#039;&#039;&#039;dst&#039;&#039;&#039;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SRC&#039;&#039;&#039; and &#039;&#039;&#039;DST&#039;&#039;&#039; in the instuction above are as follows (not all combinations are available -- see the following table):&lt;br /&gt;
* &#039;&#039;&#039;B&#039;&#039;&#039;: Balanced ternary integer (64-bit/40-trit)&lt;br /&gt;
* &#039;&#039;&#039;D&#039;&#039;&#039;: Double precision floating point (64-bit)&lt;br /&gt;
* &#039;&#039;&#039;F&#039;&#039;&#039;: Single precision / simple precision floating point (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;I&#039;&#039;&#039;: Binary integer (32-bit)&lt;br /&gt;
* &#039;&#039;&#039;P&#039;&#039;&#039;: Ternary posit (128-bit/80-trit)&lt;br /&gt;
* &#039;&#039;&#039;T&#039;&#039;&#039;: Ternary takum (128-bit/80-trit)&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
|+ Instruction Opcodes (From Row \ To Column)&lt;br /&gt;
! !! B !! D !! F !! I !! P !! T&lt;br /&gt;
|-&lt;br /&gt;
! B&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| B2I &lt;br /&gt;
| B2P &lt;br /&gt;
| B2T&lt;br /&gt;
|-&lt;br /&gt;
! D&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| D2F &lt;br /&gt;
| D2I &lt;br /&gt;
| D2P &lt;br /&gt;
| D2T&lt;br /&gt;
|-&lt;br /&gt;
! F&lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| F2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! I&lt;br /&gt;
| I2B &lt;br /&gt;
| I2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|-&lt;br /&gt;
! P&lt;br /&gt;
| P2B &lt;br /&gt;
| P2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| P2T&lt;br /&gt;
|-&lt;br /&gt;
! T&lt;br /&gt;
| T2B &lt;br /&gt;
| T2D &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | - &lt;br /&gt;
| T2P &lt;br /&gt;
| style=&amp;quot;background:#ececec; color:gray;&amp;quot; | -&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Comparison Operations ==&lt;br /&gt;
&lt;br /&gt;
=== Binary integer comparison instructions ===&lt;br /&gt;
&lt;br /&gt;
The comparison instructions are binary operations (each operand is a 32-bit binary integer) that leave at the top of the stack 0 (zero) or 1 (one), depending on the result of the comparison: respectively, &#039;&#039;&#039;false&#039;&#039;&#039; or &#039;&#039;&#039;true&#039;&#039;&#039; (32-bit binary integer). The value may be directly used to perform conditional jumps (e.g., JZ, JNZ), that use the value of the top of the stack instead of relying on special processor registers (&amp;quot;flags&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | EQ&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;equiv;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ne;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;not equal to&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | GE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following consider unsigned 32-bit binary integer operands (the result is also a 32-bit binary integer):&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;gt;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | UGE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;ge;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;greater than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULE&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;le;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than or equal to&#039;&#039; for unsigned integers&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ULT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;lt;b&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &#039;&#039;less than&#039;&#039; for unsigned integers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Comparison operators for real numbers ===&lt;br /&gt;
&lt;br /&gt;
The DCMP operator compares two double precision binary floating point numbers (64 bits). The result is a 32-bit binary integer value: less than 0, if the first operand is lower than the second; 0, if they are equal; greater than 0, otherwise. &amp;lt;!--P3CMP (for ternary posits) and T3CMP (for ternary takums) work in a similar way. Note that posits and takums are natively compared using Kleene logic (the operators below translate that into Boolean logic).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | DCMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b&lt;br /&gt;
&amp;lt;!--|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | P3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit posits; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | T3CMP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ i &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | &amp;quot;compare&amp;quot; -- i&amp;amp;lt;0, a&amp;amp;lt;b; i&amp;amp;equiv;0, a&amp;amp;equiv;b; i&amp;amp;gt;0, a&amp;amp;gt;b (&#039;&#039;&#039;a&#039;&#039;&#039; and &#039;&#039;&#039;b&#039;&#039;&#039; are 128-bit/80-trit takums; &#039;&#039;&#039;i&#039;&#039;&#039; is a 32-bit binary integer)--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bitwise Operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take and 32-bit binary integer operands. The result is also a 32-bit binary integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise negation, i.e., one&#039;s complement&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | AND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | OR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise OR operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | XOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;oplus;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Bitwise XOR (exclusive OR) operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ternary Kleene logic operations ==&lt;br /&gt;
&lt;br /&gt;
These operators take balanced ternary (64-bit/40-trit) integer operands. Note that these operators do not short-circuit Kleene logic with KAND/KOR. The result is also a balanced ternary (64-bit/40-trit) integer.&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KNOT &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ ~a &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | NOT operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KAND &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;and;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | AND operation&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | KOR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a&amp;amp;or;b &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | OR operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rotation and Shift Operations ==&lt;br /&gt;
&lt;br /&gt;
Shift and rotation operations have as maximum value the number of bits of the underlying processor register (32 bits in a ix86-family processor). Safe operation for values above that limit is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rl&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ROTR &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;rr&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Rotate &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTL &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;lt;&amp;lt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the left&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRU &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | SHTRS &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value nbits &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&amp;gt;&amp;gt;&amp;gt;bits &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Shift &#039;&#039;&#039;value&#039;&#039;&#039; &#039;&#039;&#039;nbits&#039;&#039;&#039; to the right (signed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Definition ==&lt;br /&gt;
&lt;br /&gt;
The following sections cover defining and calling functions.&lt;br /&gt;
&lt;br /&gt;
=== Starting a function ===&lt;br /&gt;
&lt;br /&gt;
Each function must allocate space for its local variables. This is done immediately after being called and before any other processing. The relevant operations are ENTER (to specify a given memory amount) and START (no space is reserved for local variables. Note that these operations do more than manipulate the stack: they also create an activation register for the function, i.e., they update the frame pointer and define a new stack frame.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | ENTER bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp #bytes &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Starts a function: pushes the frame pointer (activation register) to the stack and allocates space for local variables (&#039;&#039;&#039;bytes&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | START &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Equivalent to &amp;quot;ENTER 0&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Leaving a function ===&lt;br /&gt;
&lt;br /&gt;
STFVAL32I/STFVAL32F or STFVAL64I/STFVAL64F must be called to specify return values in accordance with C conventions. Only return values that fit in the indicated registers need these operations. Other return values are passed by pointer.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 32-bit integer value from the stack (to eax)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64I&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a 64-bit integer value from the stack (to eax:edx)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a single-precision (32-bit) floating point value from the stack (to st0)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | STFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes a double-precision (64-bit) floating point value from the stack (to st0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that balanced-ternary numbers are represented by 64-bit binary numbers. Takums cannot be directly returned (they must be returned via pointer).&lt;br /&gt;
&lt;br /&gt;
The stack frame is destroyed by the LEAVE operation. This action must be performed immediately before returning control to the caller (with RET).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAVE &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ fp ... &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Ends a function: restores the frame pointer (activation register) and destroys the function-local stack data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
After the function&#039;s stack frame is destroyed and the activation register is restored to the caller, control must also be returned to the caller (i.e., IP must be updated).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RET&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ addr&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function (the stack must contain the return address)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | RETN bytes&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes addr &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Returns from a function and removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the caller&#039;s stack after removing the return address. This is more or less the same as &amp;quot;RET+TRASH bytes&amp;quot;. &#039;&#039;&#039;Note that this is not compatible with the Cdecl calling conventions.&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Function Calls ==&lt;br /&gt;
&lt;br /&gt;
In a stack machine the arguments for a function call are already in the stack. Thus, it is not necessary to put them there (it is enough not to remove them).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | CALL name&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Calls the &#039;&#039;&#039;name&#039;&#039;&#039;d function. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | BRANCH &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ return-address&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Invokes a function at the &#039;&#039;&#039;address&#039;&#039;&#039; indicated at the top of the stack. The &#039;&#039;&#039;return-address&#039;&#039;&#039; is pushed to the stack.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When building functions that conform to the C calling convention, the arguments are destroyed by the caller, &#039;&#039;after&#039;&#039; the return of the callee, using TRASH and stating the total size (i.e., for all arguments). &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | TRASH bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ #bytes &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Removes &#039;&#039;&#039;bytes&#039;&#039;&#039; from the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
To recover the returned value by the callee, and put it in the stack, the caller must call LDFVAL32I (32-bit integer value in eax) or LDFVAL32F (32-bit single-precision floating point value in st0). An analogous procedure is valid for LDFVAL64I (64-bit integer value in eax:edx) and LDFVAL64F (64-bit double-precision floating point value in st0).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax register to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64I &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the eax:edx registers to the stack&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL32F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (32 bits, single precision)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LDFVAL64F&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Pushes the return &#039;&#039;&#039;value&#039;&#039;&#039; in the st0 register to the stack (64 bits, double precision)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Basic Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JMP label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to &#039;&#039;&#039;label&#039;&#039;&#039; (does not affect or use the stack)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | LEAP &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ address &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Unconditional jump to the &#039;&#039;&#039;address&#039;&#039;&#039; at the top of the stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Conditional Jump Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is 0 (zero)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNZ label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ value &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if the &#039;&#039;&#039;value&#039;&#039;&#039; at the top of the stack is non-zero&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following operations combine comparisons and jumps.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JEQ label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;equiv;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JNE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ne;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLE label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JLT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The following are for the unsigned versions of the comparisons.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGT label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;gt;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JUGE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;ge;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULE label&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;le;b (unsigned)&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | JULT label &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ a b &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | $ &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Jump to &#039;&#039;&#039;label&#039;&#039;&#039; if a&amp;amp;lt;b (unsigned)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other Operations ==&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NIL&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; |&lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | No action is performed&lt;br /&gt;
|-&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | NOP&lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfrow&amp;quot; | &lt;br /&gt;
! class=&amp;quot;pfdesc&amp;quot; | Generates a null operation (consumes time; does not change the processor&#039;s state)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Template:PRJCOMandatory20252026&amp;diff=17782</id>
		<title>Template:PRJCOMandatory20252026</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Template:PRJCOMandatory20252026&amp;diff=17782"/>
		<updated>2026-05-16T17:49:34Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{CDKRTS|CDK21|libcdk21-202605161833.tar.bz2|RTS7|librts7-202605092235.tar.bz2}}&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Libcdk21-202605161833.tar.bz2&amp;diff=17781</id>
		<title>File:Libcdk21-202605161833.tar.bz2</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Libcdk21-202605161833.tar.bz2&amp;diff=17781"/>
		<updated>2026-05-16T17:49:12Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Material_de_Apoio_ao_Desenvolvimento&amp;diff=17780</id>
		<title>Compiladores/Projecto de Compiladores/Material de Apoio ao Desenvolvimento</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Material_de_Apoio_ao_Desenvolvimento&amp;diff=17780"/>
		<updated>2026-05-16T17:48:58Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Material de Apoio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJHEADER}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&amp;lt;!-- &#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A DISPONIBILIZAR BREVEMENTE&amp;lt;/font&amp;gt;&#039;&#039;&#039; --&amp;gt;&lt;br /&gt;
== Material de Apoio == &lt;br /&gt;
&lt;br /&gt;
O projecto, escrito em C++, deve ser desenvolvido considerando os princípios de desenvolvimento de compiladores, assim como os da boa programação com objectos e os aspectos de arquitectura dos padrões de desenho aplicáveis. Notar que esta tarefa está implicitamente facilitada pelo material de apoio, que condiciona o desenvolvimento do compilador.&lt;br /&gt;
&lt;br /&gt;
O código presente nas bibliotecas de apoio (já instalado na máquina virtual) ao desenvolvimento do projecto é de uso obrigatório:&lt;br /&gt;
&lt;br /&gt;
* CDK [[media:libcdk21-202605161833.tar.bz2]] - código de base para o desenvolvimento do compilador&lt;br /&gt;
* RTS [[media:librts7-202605092235.tar.bz2]] - código de base para os programas gerados pelo compilador (runtime)&lt;br /&gt;
&lt;br /&gt;
{{CVSCode|Notar que o [[Compiladores/Projecto de Compiladores/Repositório GIT|repositório GIT]] já contém uma versão do projecto a desenvolver. Isto significa que &#039;&#039;antes&#039;&#039; de se começar a programar, o projecto deve ser obtido a partir do repositório.}}&lt;br /&gt;
&lt;br /&gt;
== Pacotes binários para instalação ==&lt;br /&gt;
&lt;br /&gt;
O manterial de apoio está disponível para instalação directa (não é necessário compilar) através do repositório:&lt;br /&gt;
* https://download.opensuse.org/repositories/home:/d4vid:/co26/openSUSE_Tumbleweed/&lt;br /&gt;
&lt;br /&gt;
Este repositório pode ser adicionado a um openSUSE previamente instalado através do comando:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;zypper ar https://download.opensuse.org/repositories/home:/d4vid:/co26/openSUSE_Tumbleweed/ CO26&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;zypper refresh&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Uma vez adicionado o repositório, os pacotes acima podem ser instalados através dos comandos:&lt;br /&gt;
&lt;br /&gt;
 zypper install libcdk21-devel librts7-devel&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Este material já está instalado na [[Compiladores/Projecto de Compiladores/Máquina Virtual|máquina virtual da disciplina]].}}&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores|P]]&lt;br /&gt;
[[category:Compiladores|P]]&lt;br /&gt;
[[category:Ensino|P]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17779</id>
		<title>Compiladores/Projecto de Compiladores/Projecto 2025-2026/Manual de Referência da Linguagem P6</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17779"/>
		<updated>2026-05-16T17:02:56Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Exemplos e Testes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20252026}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&amp;lt;!--&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;RASCUNHO&#039;&#039;&#039;&amp;lt;/font&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;ÉPOCA NORMAL&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;P6&#039;&#039;&#039; é 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]].&lt;br /&gt;
&lt;br /&gt;
= Tipos de Dados =&lt;br /&gt;
&lt;br /&gt;
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados básicos, apenas alguns dos quais são compatíveis com a [https://en.wikipedia.org/wiki/C_(programming_language) linguagem C]. O alinhamento em memória binária é sempre a 32 bits. Note-se que alguns dos tipos de dados são ternários e devem ser manipulados com as funções das ALUs disponibilizadas.&lt;br /&gt;
&lt;br /&gt;
* Tipos numéricos: os inteiros são [https://en.wikipedia.org/wiki/Balanced_ternary ternários equilibrados], ocupam 40 trits (empacotados em 64 bits); os reais são ternários e estão representados no formato [https://arxiv.org/abs/2404.18603 Takum] (note-se que a definição neste artigo é para uma representação binária e não é exactamente a que é implementada pelas ALUs ternárias em uso no projecto), ocupam 80 trits (empacotados em 128 bits).&lt;br /&gt;
* As cadeias de caracteres são vectores de caracteres binários terminados por [https://en.wikipedia.org/wiki/ASCII ASCII] NUL (carácter com o valor zero). Variáveis e literais deste tipo só podem ser utilizados em atribuições, impressões, ou como argumentos/retornos de funções. Os caracteres são valores de 8 bits não directamente manipuláveis.&lt;br /&gt;
* Os ponteiros representam endereços de objectos (de qualquer tipo) e ocupam 32 bits. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado. Note-se que não é possível usar inteiros ternários directamente em aritmética de ponteiros (têm de ser convertidos para isso).&lt;br /&gt;
&lt;br /&gt;
Os tipos suportados por cada operador e a operação a realizar são indicados na [[#Expressões|definição das expressões]].&lt;br /&gt;
&lt;br /&gt;
Existem ainda tipos associado a valores funcionais, i.e., tipos que descrevem a interface de funções (ver abaixo). Os valores em memória associados a estes tipos são efectivamente ponteiros, mas para funções e não para dados, podendo ser usados para invocar as funções correspondentes. Estes identificadores não podem ser usados como variáveis (e.g., passados como argumentos de outras funções, etc.).&amp;lt;!--Estes ponteiros não aceitam operações de aritmética de ponteiros ou de indexação (embora ponteiros para estes ponteiros as aceitem).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Manipulação de Nomes =&lt;br /&gt;
&lt;br /&gt;
Os nomes (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 dos casos. Existem ainda nomes para funções externas à linguagem P6. Tanto em P6, como em C, os nomes das funções referem directamente a posição do código dessas funções (à la C; ver &#039;&#039;&#039;extern&#039;&#039;&#039; abaixo).&lt;br /&gt;
&lt;br /&gt;
== Espaço de nomes e visibilidade dos identificadores ==&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
Os identificadores são visíveis desde a declaração até ao fim do alcance: ficheiro (globais) ou bloco (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 um bloco. É possível utilizar símbolos globais nos contextos dos blocos das funções, mas não é possível declará-los (ver [[#Símbolos globais|símbolos globais]]).&lt;br /&gt;
&lt;br /&gt;
== Validade das variáveis ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
= Convenções Lexicais =&lt;br /&gt;
&lt;br /&gt;
Para cada grupo de elementos lexicais (tokens), considera-se a maior sequência de caracteres constituindo um elemento válido. Assim, por exemplo, a designação &#039;&#039;&#039;&amp;gt;=&#039;&#039;&#039; é sempre um único elemento lexical (por oposição à situação ilegal de se terem dois símbolos: &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; seguido de &#039;&#039;&#039;=&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Caracteres brancos ==&lt;br /&gt;
&lt;br /&gt;
São considerados separadores e não representam nenhum elemento lexical: &#039;&#039;&#039;mudança de linha&#039;&#039;&#039; ASCII LF (&#039;&#039;&#039;0x0A&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039;), &#039;&#039;&#039;recuo do carreto&#039;&#039;&#039; ASCII CR (&#039;&#039;&#039;0x0D&#039;&#039;&#039;, &#039;&#039;&#039;\r&#039;&#039;&#039;), &#039;&#039;&#039;espaço&#039;&#039;&#039; ASCII SP (&#039;&#039;&#039;0x20&#039;&#039;&#039;, ⌴) e &#039;&#039;&#039;tabulação horizontal&#039;&#039;&#039; ASCII HT (&#039;&#039;&#039;0x09&#039;&#039;&#039;, &#039;&#039;&#039;\t&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Comentários ==&lt;br /&gt;
&lt;br /&gt;
Existem dois tipos de comentários, que também funcionam como elementos separadores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;explicativos&#039;&#039;&#039; -- começam com &#039;&#039;&#039;//&#039;&#039;&#039; e acabam no fim da linha; e&lt;br /&gt;
* &#039;&#039;&#039;operacionais&#039;&#039;&#039; -- começam com &#039;&#039;&#039;/*&#039;&#039;&#039; e terminam com &#039;&#039;&#039;*/&#039;&#039;&#039;, podendo estar aninhados.&lt;br /&gt;
&lt;br /&gt;
Se as sequências de início fizerem parte de uma cadeia de caracteres, não iniciam um comentário (ver [[#Cadeias de caracteres|definição das cadeias de caracteres]]).&lt;br /&gt;
&lt;br /&gt;
== Palavras-chave ==&lt;br /&gt;
&lt;br /&gt;
As seguintes palavras-chave são reservadas, não constituindo identificadores (devem ser escritas exactamente como indicado):&lt;br /&gt;
&lt;br /&gt;
* tipos: &#039;&#039;&#039;int real string void&#039;&#039;&#039;&lt;br /&gt;
* declarações: &#039;&#039;&#039;extern forward public auto&#039;&#039;&#039;&lt;br /&gt;
* instruções: &#039;&#039;&#039;if elif else while stop next return&#039;&#039;&#039;&lt;br /&gt;
* expressões: &#039;&#039;&#039;input null sizeof&#039;&#039;&#039;&lt;br /&gt;
* outras: &#039;&#039;&#039;begin end&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tipos ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais designam tipos em declarações (ver gramática): &#039;&#039;&#039;int&#039;&#039;&#039; (inteiro), &#039;&#039;&#039;real&#039;&#039;&#039; (real), &#039;&#039;&#039;string&#039;&#039;&#039; (cadeia de caracteres). &lt;br /&gt;
&lt;br /&gt;
Os tipos correspondentes a ponteiros são outros tipos delimitados por &#039;&#039;&#039;[&#039;&#039;&#039; e &#039;&#039;&#039;]&#039;&#039;&#039;, designando uma indirecção e não o objecto directo (ver gramática).&lt;br /&gt;
&lt;br /&gt;
Note-se que, quando se tem uma declaração &#039;&#039;&#039;extern&#039;&#039;&#039;, os tipos correspondem aos compatíveis com a linguagem C na mesma arquitectura ix86 de 32 bits, i.e., &#039;&#039;&#039;int&#039;&#039;&#039; corresponde a  um número binário inteiro em [https://en.wikipedia.org/wiki/Two%27s_complement complemento para 2] (32 bits), &#039;&#039;&#039;real&#039;&#039;&#039; coresponde a uma representação segundo a norma [https://en.wikipedia.org/wiki/IEEE_754 IEEE 754] de dupla precisão (64 bits), devendo ser convertidos de e para os tipos nativos da linguage P6 sempre que necessário (ver RTS).&lt;br /&gt;
&lt;br /&gt;
== Operadores de expressões ==&lt;br /&gt;
&lt;br /&gt;
São considerados operadores os elementos lexicais apresentados na definição das expressões.&lt;br /&gt;
&lt;br /&gt;
== Delimitadores e terminadores ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais são delimitadores/terminadores: &lt;br /&gt;
* &#039;&#039;&#039;,&#039;&#039;&#039; (vírgula)&lt;br /&gt;
* &#039;&#039;&#039;;&#039;&#039;&#039; (ponto e vírgula)&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; (operações de impressão)&lt;br /&gt;
* &#039;&#039;&#039;(&#039;&#039;&#039; e &#039;&#039;&#039;)&#039;&#039;&#039; (delimitadores de expressões)&lt;br /&gt;
* &#039;&#039;&#039;{&#039;&#039;&#039; e &#039;&#039;&#039;}&#039;&#039;&#039; (delimitadores de blocos)&lt;br /&gt;
&lt;br /&gt;
== Identificadores (nomes) ==&lt;br /&gt;
&lt;br /&gt;
São iniciados por uma letra, seguindo-se 0 (zero) ou mais letras ou dígitos. 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.&lt;br /&gt;
&lt;br /&gt;
== Literais ==&lt;br /&gt;
&lt;br /&gt;
São notações para valores constantes de alguns tipos da linguagem (não confundir com constantes, i.e., identificadores que, em algumas linguagens, designam elementos cujo valor não pode ser alterado durante a execução do programa).&lt;br /&gt;
&lt;br /&gt;
=== Inteiros ===&lt;br /&gt;
&lt;br /&gt;
Um literal inteiro é um número não negativo (mas ver a seguir). Números negativos podem ser construídos pela aplicação do operador de negação unária (&#039;&#039;&#039;-&#039;&#039;&#039;) a um literal (sempre positivo).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros decimais são constituídos por sequências de 1 (um) ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;9&#039;&#039;&#039;, em que o primeiro digito não é 0 (zero), excepto no caso do número 0 (zero). Neste caso, é composto apenas pelo dígito 0 (zero) (em qualquer base).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 9 começam sempre pelo dígito 0 (zero), sendo seguidos de um ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;8&#039;&#039;&#039; (note-se que &#039;&#039;&#039;09&#039;&#039;&#039; é um literal inválido em base 9). Exemplo: &#039;&#039;&#039;086 = 78&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 3 (equilibrada) começam sempre com a sequência &#039;&#039;&#039;0t&#039;&#039;&#039;, seguida de um ou mais símbolos dessa base: &#039;&#039;&#039;-&#039;&#039;&#039; (valor &#039;&#039;&#039;-1&#039;&#039;&#039;), &#039;&#039;&#039;0&#039;&#039;&#039; (valor &#039;&#039;&#039;0&#039;&#039;&#039;) e &#039;&#039;&#039;+&#039;&#039;&#039; (valor &#039;&#039;&#039;1&#039;&#039;&#039;). Estes literais podem ser intrinsecamente negativos. Exemplos: &#039;&#039;&#039;0t+0-0 = 24&#039;&#039;&#039;; &#039;&#039;&#039;0t-0+0 = -24&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Se não for possível representar um literal na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
&lt;br /&gt;
=== Reais em formato Takum3 ===&lt;br /&gt;
&lt;br /&gt;
Os literais reais (sempre positivos) são expressos tal como em C (exclusivamente em base 10). &lt;br /&gt;
&lt;br /&gt;
Não existem literais negativos (números negativos resultam da operação unária &#039;&#039;&#039;-&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Note-se que um literal sem &#039;&#039;&#039;.&#039;&#039;&#039; (ponto decimal) nem parte exponencial é do tipo inteiro.&lt;br /&gt;
&lt;br /&gt;
Note-se que, apesar de C normalmente usar uma representação interna em binário no formato IEEE 754, a linguagem P6 usa um formato, representado em ternário, completamente diferente (embora a forma de escrita dos literais seja a mesma).&lt;br /&gt;
&lt;br /&gt;
Exemplos: &#039;&#039;&#039;3.14&#039;&#039;&#039;, &#039;&#039;&#039;1E3&#039;&#039;&#039; = 1000 (número inteiro representado como real). &#039;&#039;&#039;12.34e-24&#039;&#039;&#039; = 12.34 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; (notação cientifica).&lt;br /&gt;
&amp;lt;!--Se não for possível representar um literal real na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cadeias de caracteres ===&lt;br /&gt;
&lt;br /&gt;
As cadeias de caracteres são delimitadas por aspas (&#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;) e podem conter quaisquer caracteres, excepto ASCII NUL (0x00) e ASCII LF (0x0A). Nas cadeias, os delimitadores de comentários não têm significado especial. Se for escrito um literal que contenha &#039;&#039;&#039;\0&#039;&#039;&#039;, então a cadeia termina nessa posição. Exemplo: &#039;&#039;&#039;ab\0xy&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;ab&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
É possível designar caracteres por sequências especiais (iniciadas por &#039;&#039;&#039;\&#039;&#039;&#039;), especialmente úteis quando não existe representação gráfica directa. As sequências especiais correspondem aos caracteres ASCII HT, LF e CR (&#039;&#039;&#039;\t&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039; e &#039;&#039;&#039;\r&#039;&#039;&#039;, respectivamente), aspa (&#039;&#039;&#039;\&amp;quot;&#039;&#039;&#039;). &#039;&#039;backslash&#039;&#039; (&#039;&#039;&#039;\\&#039;&#039;&#039;), ou a quaisquer outros especificados através de 1 a 3 dígitos em base 8, designando valores de 8 bits (e.g., &#039;&#039;&#039;\012&#039;&#039;&#039; ou apenas &#039;&#039;&#039;\12&#039;&#039;&#039; se o carácter seguinte não representar um dígito em base 8). Exemplo: &#039;&#039;&#039;xy\012z&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;xy\12z&#039;&#039;&#039; e que &#039;&#039;&#039;xy\nz&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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: &#039;&#039;&#039;&amp;quot;ab&amp;quot;&#039;&#039;&#039; &#039;&#039;&#039;&amp;quot;cd&amp;quot;&#039;&#039;&#039; é o mesmo que &#039;&#039;&#039;&amp;quot;abcd&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Ponteiros ===&lt;br /&gt;
&lt;br /&gt;
O único literal admissível para ponteiros corresponde ao ponteiro nulo e é indicado pela palavra-chave &#039;&#039;&#039;null&#039;&#039;&#039;. Este literal é compatível com todos os tipos de ponteiro. Os inteiros não são convertíveis em ponteiros, pelo que o valor &#039;&#039;&#039;0&#039;&#039;&#039; (zero) não é um valor inicial admissível para ponteiros.&lt;br /&gt;
&lt;br /&gt;
Note-se que a aritmética de ponteiros é possível apenas com inteiros binários, mas não com inteiros ternários (estes devem ser convertidos para binário, caso seja necessário).&lt;br /&gt;
&lt;br /&gt;
= Gramática =&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; e &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;. Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! style=&amp;quot;width: 140px; font-weight: normal;&amp;quot; | &#039;&#039;ficheiro&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;programa-principal&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;declaração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;tipo&#039;&#039; &#039;&#039;identificador&#039;&#039; [ &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] [ &#039;&#039;&#039;auto&#039;&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;programa-principal&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;begin&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;end&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;variáveis&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;variáveis&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;int&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;real&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;string&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;void&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;[&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;]&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;tipos&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipos&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;{&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;}&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!!&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;stop&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;next&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;return&#039;&#039;&#039; [ &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;instrução-condicional&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;instrução-de-iteração&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-condicional&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;if&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt;  &#039;&#039;&#039;elif&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;&#039;else&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-de-iteração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;while&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;expressões&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tipos, identificadores, literais e definição de expressões ==&lt;br /&gt;
&lt;br /&gt;
Algumas definições foram omitidas da gramática: tipos de dados. qualificadores e variável (ver [[#Declarações de variáveis|declarações de variáveis]]), identificador (ver [[#Identificadores (nomes)|identificadores]]), literal (ver [[#Literais|literais]]); expressão (ver [[#Expressões|expressões]]). &amp;lt;!--Note-se que &#039;&#039;função&#039;&#039; é qualquer especificação de função (corpo ou ponteiro com o tipo apropriado). Neste sentido, as funções contam como expressões primitivas.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Quanto a tipos de dados, &#039;&#039;&#039;int&#039;&#039;&#039; designa valores inteiros, &#039;&#039;&#039;real&#039;&#039;&#039; designa valores reais, &#039;&#039;&#039;string&#039;&#039;&#039; designa cadeias de caracteres. Os ponteiros são tipos compostos por um tipo entre parênteses rectos, e.g., &#039;&#039;&#039;[int]&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Os tipos funcionais são definidos a partir dos tipos de dados anteriormente descritos e do tipo especial &#039;&#039;&#039;void&#039;&#039;&#039; (ver a seguir). O tipo é indicado com o formato indicado na gramática, i.e., tipo de retorno seguido dos tipos dos argumentos (zero ou mais separados por vírgulas). Estes tipos servem para declarar símbolos de função sem as definir.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Um ponteiro declarado com um tipo de função indica o endereço da função correspondente. Estes ponteiros não suportam aritmética de ponteiros.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
O tipo &#039;&#039;&#039;void&#039;&#039;&#039; apenas pode ser usado para indicar a ausência de retorno ou para declarar um ponteiro genérico. Neste caso, o aninhamento é irrelevante, i.e., &#039;&#039;&#039;[void]&#039;&#039;&#039; e &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[void]]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; são equivalentes. Um ponteiro deste tipo é compatível com todos os outros tipos de ponteiros. A aritmética de ponteiros decrementa/incrementa em uma unidade o valor de um ponteiro do tipo &#039;&#039;&#039;[void]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Left-values ==&lt;br /&gt;
&lt;br /&gt;
Os &#039;&#039;left-values&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
== Ficheiros ==&lt;br /&gt;
&lt;br /&gt;
Um ficheiro é designado por principal se contiver a função principal (onde se inicia o programa).&lt;br /&gt;
&lt;br /&gt;
== Declaração de variáveis ==&lt;br /&gt;
&lt;br /&gt;
Uma declaração de variável indica sempre um tipo de dados (implícito ou explícito) e um identificador.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
&lt;br /&gt;
* Inteiro: &#039;&#039;&#039;int i&#039;&#039;&#039;&lt;br /&gt;
* Real: &#039;&#039;&#039;real r&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres: &#039;&#039;&#039;string s&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro para inteiro: &#039;&#039;&#039;[int] p1&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para real: &#039;&#039;&#039;[real] p2&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;double*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para cadeia de caracteres: &#039;&#039;&#039;[string] p3&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;char**&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para ponteiro para inteiro: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[int]]&amp;lt;/nowiki&amp;gt; p4&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int**&#039;&#039;&#039; em C)&lt;br /&gt;
&lt;br /&gt;
É possível usar o pseudo-tipo &#039;&#039;&#039;auto&#039;&#039;&#039; se a declaração tiver um valor inicial: neste caso, o tipo é o do valor inicial.&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
* Variável inteira: &#039;&#039;&#039;auto i = 1&#039;&#039;&#039;&lt;br /&gt;
* Variável real: &#039;&#039;&#039;auto f = 2.0&#039;&#039;&#039;&lt;br /&gt;
* etc.&lt;br /&gt;
&lt;br /&gt;
== Símbolos globais ==&lt;br /&gt;
&lt;br /&gt;
Por omissão, os símbolos são privados a um módulo, não podendo ser importados por outros módulos.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;public&#039;&#039;&#039; permite declarar um identificador como público, tornando-o acessível a partir de outros módulos. Quando usado com a palavra-chave &#039;&#039;&#039;auto&#039;&#039;&#039;, esta é opcional. Note-se que a declaração de uma variável tem de ter sempre, ou o qualificador, ou o tipo, podendo estar ambos presentes.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;forward&#039;&#039;&#039; permite declarar num módulo variáveis ou funções definidas noutros módulos. Neste caso, não pode ser especificado o valor inicial das variáveis, pelo que não é possível o uso de &#039;&#039;&#039;auto&#039;&#039;&#039; em conjunto com &#039;&#039;&#039;forward&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;extern&#039;&#039;&#039; deve ser usada para declarar símbolos de função com tipos diferentes dos dos nativos da da linguagem P6, e.g. para importar funções definidas em C. Além de poderem ser usados para chamar as funções que designam, os símbolos assim declarados podem ser utilizados com valores convertidos de forma apropriada.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Declarar variável privada ao módulo: &#039;&#039;&#039;real r1 = 22.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public real r2 = 7.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public auto r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Usar definição externa de variável pública: &#039;&#039;&#039;forward real r2&#039;&#039;&#039;&lt;br /&gt;
* Declarar função (nativa P6) definida externamente: &#039;&#039;&#039;forward int&amp;lt;int&amp;gt; factorial&#039;&#039;&#039;&lt;br /&gt;
* Declarar função definida noutra linguagem (e.g. em C): &#039;&#039;&#039;extern [void]&amp;lt;int&amp;gt; malloc&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inicialização ==&lt;br /&gt;
&lt;br /&gt;
Quando existe, é a designação do objecto que segue o símbolo &#039;&#039;&#039;=&#039;&#039;&#039;: inteiro, real, cadeia de caracteres, ou 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.&amp;lt;!-- A associação de valores funcionais a variáveis pode ser realizada quando os tipos forem covariantes. As cadeias de caracteres são (possivelmente) inicializadas com uma lista não nula de valores sem separadores.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A palavra &#039;&#039;&#039;auto&#039;&#039;&#039; pode ser usada em lugar do tipo para declarar uma variável. Quando usada, o tipo da variável é inferido a partir do valor inicial (nestes casos, o valor inicial é obrigatório).&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Inteiro (literal): &#039;&#039;&#039;int i = 3&#039;&#039;&#039;&lt;br /&gt;
* Inteiro (expressão): &#039;&#039;&#039;int i = j + 1&#039;&#039;&#039;&lt;br /&gt;
* Real (literal): &#039;&#039;&#039;real r = 3.2&#039;&#039;&#039;&lt;br /&gt;
* Real (expressão): &#039;&#039;&#039;real r = i - 2.5&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literal): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literais): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot; &amp;quot;mãe&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (literal): &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[real]]] p&amp;lt;/nowiki&amp;gt; = null&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (expressão): &#039;&#039;&#039;[int] p = q + 1&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;!--* Função:&lt;br /&gt;
 int&amp;lt;int&amp;gt; f1&lt;br /&gt;
 int&amp;lt;real&amp;gt; g1&lt;br /&gt;
 real&amp;lt;int&amp;gt; g2&lt;br /&gt;
 int&amp;lt;int&amp;gt; f2 = f1  // ok: mesmo tipo&lt;br /&gt;
 f2 = g1 // ok: tipos covariantes&lt;br /&gt;
 f2 = g2 // ERRADO&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Funções =&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Declaração ==&lt;br /&gt;
&lt;br /&gt;
As funções têm um nome que é também o endereço dessa função. O tipo de retorno de uma função que não produz valores de retorno é &#039;&#039;&#039;void&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
As funções que recebam argumentos devem indicá-los no cabeçalho. Funções sem argumentos definem um cabeçalho vazio. Os qualificadores de exportação/importação &#039;&#039;&#039;public&#039;&#039;&#039; ou &#039;&#039;&#039;forward&#039;&#039;&#039; (ver símbolos globais) podem ser aplicados às funções, mas não é possível aplicá-los às declarações dos argumentos de uma função. Não é possível especificar valores por omissão para os argumentos de uma função, nem para o valor de retorno.&lt;br /&gt;
&lt;br /&gt;
A declaração de um ponteiro para uma função (ou, de forma equivalente, do seu nome) é utilizada para caracterizar 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). &amp;lt;!--Caso a declaração tenha corpo, define-se uma nova função.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Invocação ==&lt;br /&gt;
&lt;br /&gt;
Uma função pode ser invocada através do seu nome. &amp;lt;!--ou de um ponteiro do tipo apropriado que refira essa função (ponteiro não nulo). O símbolo &#039;&#039;&#039;@&#039;&#039;&#039; pode ser usado dentro da própria função para efectuar uma invocação recursiva. Não é possível o uso de &#039;&#039;&#039;@&#039;&#039;&#039; no programa principal.--&amp;gt;&lt;br /&gt;
Se existirem argumentos, na invocação da função, o nome é 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 menos de conversões implícitas). A ordem dos parâmetros actuais deverá ser a mesma dos argumentos formais da função a ser invocada.&lt;br /&gt;
&lt;br /&gt;
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. Note que o retorno de entidades com dimensão superior a 64 bits deve fazer-se através da reserva de espaço para o retorno no chamador e passando um ponteiro para esse espaço como primeiro argumento do chamado.&lt;br /&gt;
&lt;br /&gt;
== Corpo ==&lt;br /&gt;
&lt;br /&gt;
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 de exportação (&#039;&#039;&#039;public&#039;&#039;&#039;) ou de importação (&#039;&#039;&#039;forward&#039;&#039;&#039; ou &#039;&#039;&#039;extern&#039;&#039;&#039;) (ver [[#Símbolos globais|símbolos globais]]) dentro do corpo de uma função.&lt;br /&gt;
&lt;br /&gt;
Uma instrução &#039;&#039;&#039;return&#039;&#039;&#039; causa a interrupção da função. O valor devolvido por uma função, através de expressão usada como argumento da instrução &#039;&#039;&#039;return&#039;&#039;&#039;, deve ser do tipo declarado no cabeçalho da função. Ver casos especiais acima.&lt;br /&gt;
&lt;br /&gt;
É um erro especificar um valor de retorno se a função for declarada como não retornando um valor (indicada como &#039;&#039;&#039;void&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Qualquer bloco (usado, por exemplo, numa instrução condicional ou de iteração) pode definir variáveis locais. &amp;lt;!--, cujos valores podem ser outras funções. Funções definidas dentro de um bloco não têm acesso às variáveis em contexto na função actual onde ocorrem.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Função principal e execução de programas ==&lt;br /&gt;
&lt;br /&gt;
Um programa é a sequência de instruções que seguem as declarações globais num ficheiro, delimitadas pelas palavras-chave &#039;&#039;&#039;begin&#039;&#039;&#039; e &#039;&#039;&#039;end&#039;&#039;&#039;. Esta sequência forma o que em algumas linguagens se chama a função principal. Os argumentos com que o programa foi chamado podem ser obtidos através de funções &#039;&#039;&#039;argc&#039;&#039;&#039; (devolve o número de argumentos); &#039;&#039;&#039;argv&#039;&#039;&#039; (devolve o n-ésimo argumento como uma cadeia de caracteres, com n&amp;gt;0); e &#039;&#039;&#039;envp&#039;&#039;&#039; (devolve a n-ésima variável de ambiente como uma cadeia de caracteres, com n&amp;gt;0). Apenas um dos módulos do programa pode definir a função principal, i.e., se existirem vários módulos, apenas um deles pode conter mais do que declarações de variáveis globais.&lt;br /&gt;
&lt;br /&gt;
 extern int&amp;lt;&amp;gt; argc&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; argv&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; envp&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
= Instruções =&lt;br /&gt;
&lt;br /&gt;
Excepto quando indicado, as instruções são executadas em sequência.&lt;br /&gt;
&lt;br /&gt;
== Blocos ==&lt;br /&gt;
&lt;br /&gt;
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 definir funções dentro de blocos, mas é possível declarar ponteiros de função locais.&lt;br /&gt;
&lt;br /&gt;
A visibilidade das variáveis é limitada ao bloco em que foram declaradas. As entidades declaradas podem ser directamente utilizadas em sub-blocos ou passadas como argumentos para funções chamadas dentro do bloco. Caso os identificadores usados para definir as variáveis locais já estejam a ser utilizados para definir outras entidades ao alcance do bloco, o novo identificador passa a referir uma nova entidade definida no bloco até que ele termine (a entidade previamente definida continua a existir, mas não pode ser directamente referida pelo seu nome). Esta regra é também válida relativamente a&lt;br /&gt;
argumentos de funções (ver corpo das funções).&lt;br /&gt;
&lt;br /&gt;
== Instrução condicional ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento semelhante ao da instrução &#039;&#039;&#039;if-else&#039;&#039;&#039; em C. As partes correspondentes a &#039;&#039;&#039;elif&#039;&#039;&#039; comportam-se como encadeamentos de instruções condicionais na parte &#039;&#039;&#039;else&#039;&#039;&#039; de um &#039;&#039;&#039;if-else&#039;&#039;&#039; à la C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de iteração ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento idêntico ao da instrução &#039;&#039;&#039;while&#039;&#039;&#039; em C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de terminação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;stop&#039;&#039;&#039; termina o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;break&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de continuação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;next&#039;&#039;&#039; reinicia o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;continue&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de retorno ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;return&#039;&#039;&#039;, se existir, é a última instrução do seu bloco. Ver comportamento na [[#Corpo|descrição do corpo de uma função]].&lt;br /&gt;
&lt;br /&gt;
== Expressões como instruções ==&lt;br /&gt;
&lt;br /&gt;
As expressões utilizadas como instruções são sempre avaliadas, mesmo que não produzam efeitos secundários.&lt;br /&gt;
&lt;br /&gt;
== Instruções de impressão ==&lt;br /&gt;
&lt;br /&gt;
As notações &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; podem ser utilizadas para apresentar valores na saída do programa. A primeira forma apresenta os valores sem mudar de linha; a segunda forma apresenta os valores mudando de linha depois de os apresentar a todos. Quando existe mais de uma expressão, as várias expressões são apresentadas sem separação. Valores numéricos (inteiros ou reais) são impressos em decimal. As cadeias de caracteres são impressas na codificação nativa. Ponteiros não podem ser impressos.&lt;br /&gt;
&lt;br /&gt;
= Expressões =&lt;br /&gt;
&lt;br /&gt;
Uma expressão é uma representação algébrica de uma quantidade: todas as expressões têm um tipo e devolvem um valor.&lt;br /&gt;
&lt;br /&gt;
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]].&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
 {|&lt;br /&gt;
| &#039;&#039;&#039;Tipo de Expressão&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operadores&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Associatividade&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operandos&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Semântica&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| primária&lt;br /&gt;
| &#039;&#039;&#039;( ) [ ]&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Parênteses curvos|parênteses curvos]], [[#Indexação|indexação]], [[#Reserva de memória|reserva de memória]]&lt;br /&gt;
|-&lt;br /&gt;
| unária&lt;br /&gt;
| &#039;&#039;&#039;+ - ?&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Identidade e simétrico|identidade e simétrico]], [[#Expressão de indicação de posição|indicação de posição]]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;não&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;~&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | não associativo&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: negação&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | multiplicativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;* / %&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | aditiva&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;+ -&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias: se envolverem ponteiros, calculam: (i) deslocamentos, i.e., um dos operandos deve ser do tipo ponteiro e o outro do tipo inteiro (binário de 32 bits); (ii) diferenças de ponteiros, i.e., apenas quando se aplica o operador &#039;&#039;&#039;-&#039;&#039;&#039; a dois ponteiros do mesmo tipo (o resultado é o número de objectos do tipo apontado entre eles, representado como um valor inteiro ternário de 64 bits). Se a memória não for contígua, o resultado é indefinido.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | comparativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt; &amp;gt; &amp;lt;= &amp;gt;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | igualdade&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;== !=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;e&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for falso.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;ou&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for verdadeiro.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | atribuição&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da direita para a esquerda&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | todos os tipos&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | O valor da expressão do lado direito do operador é guardado na posição indicada pelo &#039;&#039;left-value&#039;&#039; (operando esquerdo do operador). Podem ser atribuídos valores inteiros a &#039;&#039;left-values&#039;&#039; reais (conversão automática). Nos outros casos, ambos os tipos têm de concordar. O literal &#039;&#039;&#039;null&#039;&#039;&#039; é compatível com todos os tipos de ponteiros.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Expressões primitivas ==&lt;br /&gt;
&lt;br /&gt;
As [[#Literais|expressões literais]] e a [[#Invocação|invocação de funções]] foram definidas acima.&lt;br /&gt;
&lt;br /&gt;
=== Identificadores ===&lt;br /&gt;
&lt;br /&gt;
Um identificador é uma expressão se tiver sido declarado. Um identificador pode denotar uma variável.&lt;br /&gt;
&lt;br /&gt;
Um identificador é o caso mais simples de um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;, ou seja, uma entidade que pode ser utilizada no lado esquerdo (&#039;&#039;left&#039;&#039;) de uma atribuição.&lt;br /&gt;
&lt;br /&gt;
=== Leitura ===&lt;br /&gt;
&lt;br /&gt;
A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão indicada pela palavra-chave &#039;&#039;&#039;input&#039;&#039;&#039;, que devolve o valor lido, de acordo com o tipo esperado (inteiro ou real). Caso se use como argumento dos operadores de impressão ou noutras situações que permitam vários tipos (e.g. &#039;&#039;&#039;!&#039;&#039;&#039; ou &#039;&#039;&#039;!!&#039;&#039;&#039;), deve ser lido um inteiro.&lt;br /&gt;
&lt;br /&gt;
Exemplos:  &#039;&#039;&#039;a = input&#039;&#039;&#039; (leitura para &#039;&#039;&#039;a&#039;&#039;&#039;), &#039;&#039;&#039;f(input)&#039;&#039;&#039; (leitura para argumento de função), &#039;&#039;&#039;input!!&#039;&#039;&#039; (leitura e impressão).&lt;br /&gt;
&lt;br /&gt;
=== Parênteses curvos ===&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;left-value&#039;&#039; (ver também a [[#Indexação|expressão de indexação]]).&lt;br /&gt;
&amp;lt;!--=== Funções ===&lt;br /&gt;
&lt;br /&gt;
As funções (ponteiros ou o seu código: não confundir com chamadas a funções) podem ser usadas como expressões tipificadas como funções, i.e., ponteiros para funções (mesmo quando não se usa explicitamente um ponteiro).&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
 f1(int i) -&amp;gt; int { return i + 1; }&lt;br /&gt;
 f2(int i) -&amp;gt; int { return i * 2; }&lt;br /&gt;
&lt;br /&gt;
 g(int n, int&amp;lt;int&amp;gt; fun) -&amp;gt; int { return fun(n); }&lt;br /&gt;
 &lt;br /&gt;
 begin&lt;br /&gt;
   g(3, f1)!!  // escreve 4&lt;br /&gt;
   g(3, f2)!!  // escreve 6&lt;br /&gt;
 end&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expressões resultantes de avaliação de operadores ==&lt;br /&gt;
&lt;br /&gt;
=== Indexação de ponteiros ===&lt;br /&gt;
&lt;br /&gt;
A indexação de ponteiros devolve o valor de uma posição de memória indicada por um ponteiro. Consiste em uma expressão ponteiro seguida do índice entre parênteses rectos. O resultado de uma indexação de ponteiros é um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;. Não é possível indexar ponteiros que designem funções.&lt;br /&gt;
&lt;br /&gt;
Exemplo (acesso à posição 0 da zona de memória indicada por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;p[0]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Identidade e simétrico ===&lt;br /&gt;
&lt;br /&gt;
Os operadores identidade (&#039;&#039;&#039;+&#039;&#039;&#039;) e simétrico (&#039;&#039;&#039;-&#039;&#039;&#039;) aplicam-se a inteiros e reais. Têm o mesmo significado que em análogo às operações correspondentes em C, mas operam sobre grandezas ternárias.&lt;br /&gt;
&lt;br /&gt;
=== Reserva de memória ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Exemplo (reserva vector com 5 reais, apontados por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;[real] p = [5]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de indicação de posição ===&lt;br /&gt;
&lt;br /&gt;
O operador sufixo &#039;&#039;&#039;?&#039;&#039;&#039; aplica-se a &#039;&#039;left-values&#039;&#039;, retornando o endereço (com o tipo ponteiro) correspondente.&lt;br /&gt;
&lt;br /&gt;
Exemplo (indica o endereço de &#039;&#039;&#039;a&#039;&#039;&#039;): &#039;&#039;&#039;a?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de dimensão ===&lt;br /&gt;
&lt;br /&gt;
O operador &#039;&#039;&#039;sizeof&#039;&#039;&#039; tem um único argumento e aplica-se a expressões, retornando a dimensão correspondente em bytes.&lt;br /&gt;
&lt;br /&gt;
Exemplo: &#039;&#039;&#039;sizeof(a)&#039;&#039;&#039; (dimensão de &#039;&#039;&#039;a&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
= Exemplos e Testes =&lt;br /&gt;
&lt;br /&gt;
Os exemplos abaixo não são exaustivos e não ilustram todos os aspectos da linguagem.&lt;br /&gt;
&lt;br /&gt;
Estão ainda disponíveis outros [https://gitlab.rnl.tecnico.ulisboa.pt/leic-a-co26/eval/co26 pacotes de testes].&lt;br /&gt;
&lt;br /&gt;
O seguinte exemplo ilustra um programa com dois módulos: um que define a função &#039;&#039;&#039;factorial&#039;&#039;&#039; e outro que define a função principal.&lt;br /&gt;
&lt;br /&gt;
Definição da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;factorial.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
public factorial(int n) -&amp;gt; int {&lt;br /&gt;
  if (n &amp;gt; 1) &lt;br /&gt;
    return n * factorial(n - 1);&lt;br /&gt;
  else &lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exemplo da utilização da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;main.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
// external builtin functions (non-P6)&lt;br /&gt;
extern int&amp;lt;&amp;gt; argc;&lt;br /&gt;
extern string&amp;lt;int&amp;gt; argv;&lt;br /&gt;
extern int&amp;lt;string&amp;gt; atoi;&lt;br /&gt;
&lt;br /&gt;
// external user functions (P6)&lt;br /&gt;
forward int&amp;lt;int&amp;gt; factorial;&lt;br /&gt;
&lt;br /&gt;
// the main function&lt;br /&gt;
begin&lt;br /&gt;
  auto value = 1;&lt;br /&gt;
  &amp;quot;Teste para a função factorial.&amp;quot;!!&lt;br /&gt;
  if (argc() == 2) {&lt;br /&gt;
    string s = argv(1);&lt;br /&gt;
    value = atoi(s);&lt;br /&gt;
  }&lt;br /&gt;
  value, &amp;quot;! é &amp;quot;, factorial(value)!!&lt;br /&gt;
  return 0;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Como compilar:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
p6 --target asm factorial.p6&lt;br /&gt;
p6 --target asm main.p6&lt;br /&gt;
yasm -felf32 factorial.asm&lt;br /&gt;
yasm -felf32 main.asm&lt;br /&gt;
ld -melf_i386 -o main factorial.o main.o -lrts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Omissões e Erros =&lt;br /&gt;
&lt;br /&gt;
Casos omissos e erros serão corrigidos em futuras versões do manual de referência.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17778</id>
		<title>Compiladores/Projecto de Compiladores/Projecto 2025-2026/Manual de Referência da Linguagem P6</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17778"/>
		<updated>2026-05-16T16:50:20Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Exemplos e Testes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20252026}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&amp;lt;!--&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;RASCUNHO&#039;&#039;&#039;&amp;lt;/font&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;ÉPOCA NORMAL&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;P6&#039;&#039;&#039; é 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]].&lt;br /&gt;
&lt;br /&gt;
= Tipos de Dados =&lt;br /&gt;
&lt;br /&gt;
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados básicos, apenas alguns dos quais são compatíveis com a [https://en.wikipedia.org/wiki/C_(programming_language) linguagem C]. O alinhamento em memória binária é sempre a 32 bits. Note-se que alguns dos tipos de dados são ternários e devem ser manipulados com as funções das ALUs disponibilizadas.&lt;br /&gt;
&lt;br /&gt;
* Tipos numéricos: os inteiros são [https://en.wikipedia.org/wiki/Balanced_ternary ternários equilibrados], ocupam 40 trits (empacotados em 64 bits); os reais são ternários e estão representados no formato [https://arxiv.org/abs/2404.18603 Takum] (note-se que a definição neste artigo é para uma representação binária e não é exactamente a que é implementada pelas ALUs ternárias em uso no projecto), ocupam 80 trits (empacotados em 128 bits).&lt;br /&gt;
* As cadeias de caracteres são vectores de caracteres binários terminados por [https://en.wikipedia.org/wiki/ASCII ASCII] NUL (carácter com o valor zero). Variáveis e literais deste tipo só podem ser utilizados em atribuições, impressões, ou como argumentos/retornos de funções. Os caracteres são valores de 8 bits não directamente manipuláveis.&lt;br /&gt;
* Os ponteiros representam endereços de objectos (de qualquer tipo) e ocupam 32 bits. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado. Note-se que não é possível usar inteiros ternários directamente em aritmética de ponteiros (têm de ser convertidos para isso).&lt;br /&gt;
&lt;br /&gt;
Os tipos suportados por cada operador e a operação a realizar são indicados na [[#Expressões|definição das expressões]].&lt;br /&gt;
&lt;br /&gt;
Existem ainda tipos associado a valores funcionais, i.e., tipos que descrevem a interface de funções (ver abaixo). Os valores em memória associados a estes tipos são efectivamente ponteiros, mas para funções e não para dados, podendo ser usados para invocar as funções correspondentes. Estes identificadores não podem ser usados como variáveis (e.g., passados como argumentos de outras funções, etc.).&amp;lt;!--Estes ponteiros não aceitam operações de aritmética de ponteiros ou de indexação (embora ponteiros para estes ponteiros as aceitem).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Manipulação de Nomes =&lt;br /&gt;
&lt;br /&gt;
Os nomes (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 dos casos. Existem ainda nomes para funções externas à linguagem P6. Tanto em P6, como em C, os nomes das funções referem directamente a posição do código dessas funções (à la C; ver &#039;&#039;&#039;extern&#039;&#039;&#039; abaixo).&lt;br /&gt;
&lt;br /&gt;
== Espaço de nomes e visibilidade dos identificadores ==&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
Os identificadores são visíveis desde a declaração até ao fim do alcance: ficheiro (globais) ou bloco (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 um bloco. É possível utilizar símbolos globais nos contextos dos blocos das funções, mas não é possível declará-los (ver [[#Símbolos globais|símbolos globais]]).&lt;br /&gt;
&lt;br /&gt;
== Validade das variáveis ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
= Convenções Lexicais =&lt;br /&gt;
&lt;br /&gt;
Para cada grupo de elementos lexicais (tokens), considera-se a maior sequência de caracteres constituindo um elemento válido. Assim, por exemplo, a designação &#039;&#039;&#039;&amp;gt;=&#039;&#039;&#039; é sempre um único elemento lexical (por oposição à situação ilegal de se terem dois símbolos: &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; seguido de &#039;&#039;&#039;=&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Caracteres brancos ==&lt;br /&gt;
&lt;br /&gt;
São considerados separadores e não representam nenhum elemento lexical: &#039;&#039;&#039;mudança de linha&#039;&#039;&#039; ASCII LF (&#039;&#039;&#039;0x0A&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039;), &#039;&#039;&#039;recuo do carreto&#039;&#039;&#039; ASCII CR (&#039;&#039;&#039;0x0D&#039;&#039;&#039;, &#039;&#039;&#039;\r&#039;&#039;&#039;), &#039;&#039;&#039;espaço&#039;&#039;&#039; ASCII SP (&#039;&#039;&#039;0x20&#039;&#039;&#039;, ⌴) e &#039;&#039;&#039;tabulação horizontal&#039;&#039;&#039; ASCII HT (&#039;&#039;&#039;0x09&#039;&#039;&#039;, &#039;&#039;&#039;\t&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Comentários ==&lt;br /&gt;
&lt;br /&gt;
Existem dois tipos de comentários, que também funcionam como elementos separadores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;explicativos&#039;&#039;&#039; -- começam com &#039;&#039;&#039;//&#039;&#039;&#039; e acabam no fim da linha; e&lt;br /&gt;
* &#039;&#039;&#039;operacionais&#039;&#039;&#039; -- começam com &#039;&#039;&#039;/*&#039;&#039;&#039; e terminam com &#039;&#039;&#039;*/&#039;&#039;&#039;, podendo estar aninhados.&lt;br /&gt;
&lt;br /&gt;
Se as sequências de início fizerem parte de uma cadeia de caracteres, não iniciam um comentário (ver [[#Cadeias de caracteres|definição das cadeias de caracteres]]).&lt;br /&gt;
&lt;br /&gt;
== Palavras-chave ==&lt;br /&gt;
&lt;br /&gt;
As seguintes palavras-chave são reservadas, não constituindo identificadores (devem ser escritas exactamente como indicado):&lt;br /&gt;
&lt;br /&gt;
* tipos: &#039;&#039;&#039;int real string void&#039;&#039;&#039;&lt;br /&gt;
* declarações: &#039;&#039;&#039;extern forward public auto&#039;&#039;&#039;&lt;br /&gt;
* instruções: &#039;&#039;&#039;if elif else while stop next return&#039;&#039;&#039;&lt;br /&gt;
* expressões: &#039;&#039;&#039;input null sizeof&#039;&#039;&#039;&lt;br /&gt;
* outras: &#039;&#039;&#039;begin end&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tipos ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais designam tipos em declarações (ver gramática): &#039;&#039;&#039;int&#039;&#039;&#039; (inteiro), &#039;&#039;&#039;real&#039;&#039;&#039; (real), &#039;&#039;&#039;string&#039;&#039;&#039; (cadeia de caracteres). &lt;br /&gt;
&lt;br /&gt;
Os tipos correspondentes a ponteiros são outros tipos delimitados por &#039;&#039;&#039;[&#039;&#039;&#039; e &#039;&#039;&#039;]&#039;&#039;&#039;, designando uma indirecção e não o objecto directo (ver gramática).&lt;br /&gt;
&lt;br /&gt;
Note-se que, quando se tem uma declaração &#039;&#039;&#039;extern&#039;&#039;&#039;, os tipos correspondem aos compatíveis com a linguagem C na mesma arquitectura ix86 de 32 bits, i.e., &#039;&#039;&#039;int&#039;&#039;&#039; corresponde a  um número binário inteiro em [https://en.wikipedia.org/wiki/Two%27s_complement complemento para 2] (32 bits), &#039;&#039;&#039;real&#039;&#039;&#039; coresponde a uma representação segundo a norma [https://en.wikipedia.org/wiki/IEEE_754 IEEE 754] de dupla precisão (64 bits), devendo ser convertidos de e para os tipos nativos da linguage P6 sempre que necessário (ver RTS).&lt;br /&gt;
&lt;br /&gt;
== Operadores de expressões ==&lt;br /&gt;
&lt;br /&gt;
São considerados operadores os elementos lexicais apresentados na definição das expressões.&lt;br /&gt;
&lt;br /&gt;
== Delimitadores e terminadores ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais são delimitadores/terminadores: &lt;br /&gt;
* &#039;&#039;&#039;,&#039;&#039;&#039; (vírgula)&lt;br /&gt;
* &#039;&#039;&#039;;&#039;&#039;&#039; (ponto e vírgula)&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; (operações de impressão)&lt;br /&gt;
* &#039;&#039;&#039;(&#039;&#039;&#039; e &#039;&#039;&#039;)&#039;&#039;&#039; (delimitadores de expressões)&lt;br /&gt;
* &#039;&#039;&#039;{&#039;&#039;&#039; e &#039;&#039;&#039;}&#039;&#039;&#039; (delimitadores de blocos)&lt;br /&gt;
&lt;br /&gt;
== Identificadores (nomes) ==&lt;br /&gt;
&lt;br /&gt;
São iniciados por uma letra, seguindo-se 0 (zero) ou mais letras ou dígitos. 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.&lt;br /&gt;
&lt;br /&gt;
== Literais ==&lt;br /&gt;
&lt;br /&gt;
São notações para valores constantes de alguns tipos da linguagem (não confundir com constantes, i.e., identificadores que, em algumas linguagens, designam elementos cujo valor não pode ser alterado durante a execução do programa).&lt;br /&gt;
&lt;br /&gt;
=== Inteiros ===&lt;br /&gt;
&lt;br /&gt;
Um literal inteiro é um número não negativo (mas ver a seguir). Números negativos podem ser construídos pela aplicação do operador de negação unária (&#039;&#039;&#039;-&#039;&#039;&#039;) a um literal (sempre positivo).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros decimais são constituídos por sequências de 1 (um) ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;9&#039;&#039;&#039;, em que o primeiro digito não é 0 (zero), excepto no caso do número 0 (zero). Neste caso, é composto apenas pelo dígito 0 (zero) (em qualquer base).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 9 começam sempre pelo dígito 0 (zero), sendo seguidos de um ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;8&#039;&#039;&#039; (note-se que &#039;&#039;&#039;09&#039;&#039;&#039; é um literal inválido em base 9). Exemplo: &#039;&#039;&#039;086 = 78&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 3 (equilibrada) começam sempre com a sequência &#039;&#039;&#039;0t&#039;&#039;&#039;, seguida de um ou mais símbolos dessa base: &#039;&#039;&#039;-&#039;&#039;&#039; (valor &#039;&#039;&#039;-1&#039;&#039;&#039;), &#039;&#039;&#039;0&#039;&#039;&#039; (valor &#039;&#039;&#039;0&#039;&#039;&#039;) e &#039;&#039;&#039;+&#039;&#039;&#039; (valor &#039;&#039;&#039;1&#039;&#039;&#039;). Estes literais podem ser intrinsecamente negativos. Exemplos: &#039;&#039;&#039;0t+0-0 = 24&#039;&#039;&#039;; &#039;&#039;&#039;0t-0+0 = -24&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Se não for possível representar um literal na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
&lt;br /&gt;
=== Reais em formato Takum3 ===&lt;br /&gt;
&lt;br /&gt;
Os literais reais (sempre positivos) são expressos tal como em C (exclusivamente em base 10). &lt;br /&gt;
&lt;br /&gt;
Não existem literais negativos (números negativos resultam da operação unária &#039;&#039;&#039;-&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Note-se que um literal sem &#039;&#039;&#039;.&#039;&#039;&#039; (ponto decimal) nem parte exponencial é do tipo inteiro.&lt;br /&gt;
&lt;br /&gt;
Note-se que, apesar de C normalmente usar uma representação interna em binário no formato IEEE 754, a linguagem P6 usa um formato, representado em ternário, completamente diferente (embora a forma de escrita dos literais seja a mesma).&lt;br /&gt;
&lt;br /&gt;
Exemplos: &#039;&#039;&#039;3.14&#039;&#039;&#039;, &#039;&#039;&#039;1E3&#039;&#039;&#039; = 1000 (número inteiro representado como real). &#039;&#039;&#039;12.34e-24&#039;&#039;&#039; = 12.34 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; (notação cientifica).&lt;br /&gt;
&amp;lt;!--Se não for possível representar um literal real na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cadeias de caracteres ===&lt;br /&gt;
&lt;br /&gt;
As cadeias de caracteres são delimitadas por aspas (&#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;) e podem conter quaisquer caracteres, excepto ASCII NUL (0x00) e ASCII LF (0x0A). Nas cadeias, os delimitadores de comentários não têm significado especial. Se for escrito um literal que contenha &#039;&#039;&#039;\0&#039;&#039;&#039;, então a cadeia termina nessa posição. Exemplo: &#039;&#039;&#039;ab\0xy&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;ab&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
É possível designar caracteres por sequências especiais (iniciadas por &#039;&#039;&#039;\&#039;&#039;&#039;), especialmente úteis quando não existe representação gráfica directa. As sequências especiais correspondem aos caracteres ASCII HT, LF e CR (&#039;&#039;&#039;\t&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039; e &#039;&#039;&#039;\r&#039;&#039;&#039;, respectivamente), aspa (&#039;&#039;&#039;\&amp;quot;&#039;&#039;&#039;). &#039;&#039;backslash&#039;&#039; (&#039;&#039;&#039;\\&#039;&#039;&#039;), ou a quaisquer outros especificados através de 1 a 3 dígitos em base 8, designando valores de 8 bits (e.g., &#039;&#039;&#039;\012&#039;&#039;&#039; ou apenas &#039;&#039;&#039;\12&#039;&#039;&#039; se o carácter seguinte não representar um dígito em base 8). Exemplo: &#039;&#039;&#039;xy\012z&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;xy\12z&#039;&#039;&#039; e que &#039;&#039;&#039;xy\nz&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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: &#039;&#039;&#039;&amp;quot;ab&amp;quot;&#039;&#039;&#039; &#039;&#039;&#039;&amp;quot;cd&amp;quot;&#039;&#039;&#039; é o mesmo que &#039;&#039;&#039;&amp;quot;abcd&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Ponteiros ===&lt;br /&gt;
&lt;br /&gt;
O único literal admissível para ponteiros corresponde ao ponteiro nulo e é indicado pela palavra-chave &#039;&#039;&#039;null&#039;&#039;&#039;. Este literal é compatível com todos os tipos de ponteiro. Os inteiros não são convertíveis em ponteiros, pelo que o valor &#039;&#039;&#039;0&#039;&#039;&#039; (zero) não é um valor inicial admissível para ponteiros.&lt;br /&gt;
&lt;br /&gt;
Note-se que a aritmética de ponteiros é possível apenas com inteiros binários, mas não com inteiros ternários (estes devem ser convertidos para binário, caso seja necessário).&lt;br /&gt;
&lt;br /&gt;
= Gramática =&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; e &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;. Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! style=&amp;quot;width: 140px; font-weight: normal;&amp;quot; | &#039;&#039;ficheiro&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;programa-principal&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;declaração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;tipo&#039;&#039; &#039;&#039;identificador&#039;&#039; [ &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] [ &#039;&#039;&#039;auto&#039;&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;programa-principal&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;begin&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;end&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;variáveis&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;variáveis&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;int&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;real&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;string&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;void&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;[&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;]&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;tipos&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipos&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;{&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;}&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!!&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;stop&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;next&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;return&#039;&#039;&#039; [ &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;instrução-condicional&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;instrução-de-iteração&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-condicional&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;if&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt;  &#039;&#039;&#039;elif&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;&#039;else&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-de-iteração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;while&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;expressões&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tipos, identificadores, literais e definição de expressões ==&lt;br /&gt;
&lt;br /&gt;
Algumas definições foram omitidas da gramática: tipos de dados. qualificadores e variável (ver [[#Declarações de variáveis|declarações de variáveis]]), identificador (ver [[#Identificadores (nomes)|identificadores]]), literal (ver [[#Literais|literais]]); expressão (ver [[#Expressões|expressões]]). &amp;lt;!--Note-se que &#039;&#039;função&#039;&#039; é qualquer especificação de função (corpo ou ponteiro com o tipo apropriado). Neste sentido, as funções contam como expressões primitivas.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Quanto a tipos de dados, &#039;&#039;&#039;int&#039;&#039;&#039; designa valores inteiros, &#039;&#039;&#039;real&#039;&#039;&#039; designa valores reais, &#039;&#039;&#039;string&#039;&#039;&#039; designa cadeias de caracteres. Os ponteiros são tipos compostos por um tipo entre parênteses rectos, e.g., &#039;&#039;&#039;[int]&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Os tipos funcionais são definidos a partir dos tipos de dados anteriormente descritos e do tipo especial &#039;&#039;&#039;void&#039;&#039;&#039; (ver a seguir). O tipo é indicado com o formato indicado na gramática, i.e., tipo de retorno seguido dos tipos dos argumentos (zero ou mais separados por vírgulas). Estes tipos servem para declarar símbolos de função sem as definir.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Um ponteiro declarado com um tipo de função indica o endereço da função correspondente. Estes ponteiros não suportam aritmética de ponteiros.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
O tipo &#039;&#039;&#039;void&#039;&#039;&#039; apenas pode ser usado para indicar a ausência de retorno ou para declarar um ponteiro genérico. Neste caso, o aninhamento é irrelevante, i.e., &#039;&#039;&#039;[void]&#039;&#039;&#039; e &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[void]]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; são equivalentes. Um ponteiro deste tipo é compatível com todos os outros tipos de ponteiros. A aritmética de ponteiros decrementa/incrementa em uma unidade o valor de um ponteiro do tipo &#039;&#039;&#039;[void]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Left-values ==&lt;br /&gt;
&lt;br /&gt;
Os &#039;&#039;left-values&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
== Ficheiros ==&lt;br /&gt;
&lt;br /&gt;
Um ficheiro é designado por principal se contiver a função principal (onde se inicia o programa).&lt;br /&gt;
&lt;br /&gt;
== Declaração de variáveis ==&lt;br /&gt;
&lt;br /&gt;
Uma declaração de variável indica sempre um tipo de dados (implícito ou explícito) e um identificador.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
&lt;br /&gt;
* Inteiro: &#039;&#039;&#039;int i&#039;&#039;&#039;&lt;br /&gt;
* Real: &#039;&#039;&#039;real r&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres: &#039;&#039;&#039;string s&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro para inteiro: &#039;&#039;&#039;[int] p1&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para real: &#039;&#039;&#039;[real] p2&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;double*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para cadeia de caracteres: &#039;&#039;&#039;[string] p3&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;char**&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para ponteiro para inteiro: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[int]]&amp;lt;/nowiki&amp;gt; p4&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int**&#039;&#039;&#039; em C)&lt;br /&gt;
&lt;br /&gt;
É possível usar o pseudo-tipo &#039;&#039;&#039;auto&#039;&#039;&#039; se a declaração tiver um valor inicial: neste caso, o tipo é o do valor inicial.&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
* Variável inteira: &#039;&#039;&#039;auto i = 1&#039;&#039;&#039;&lt;br /&gt;
* Variável real: &#039;&#039;&#039;auto f = 2.0&#039;&#039;&#039;&lt;br /&gt;
* etc.&lt;br /&gt;
&lt;br /&gt;
== Símbolos globais ==&lt;br /&gt;
&lt;br /&gt;
Por omissão, os símbolos são privados a um módulo, não podendo ser importados por outros módulos.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;public&#039;&#039;&#039; permite declarar um identificador como público, tornando-o acessível a partir de outros módulos. Quando usado com a palavra-chave &#039;&#039;&#039;auto&#039;&#039;&#039;, esta é opcional. Note-se que a declaração de uma variável tem de ter sempre, ou o qualificador, ou o tipo, podendo estar ambos presentes.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;forward&#039;&#039;&#039; permite declarar num módulo variáveis ou funções definidas noutros módulos. Neste caso, não pode ser especificado o valor inicial das variáveis, pelo que não é possível o uso de &#039;&#039;&#039;auto&#039;&#039;&#039; em conjunto com &#039;&#039;&#039;forward&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;extern&#039;&#039;&#039; deve ser usada para declarar símbolos de função com tipos diferentes dos dos nativos da da linguagem P6, e.g. para importar funções definidas em C. Além de poderem ser usados para chamar as funções que designam, os símbolos assim declarados podem ser utilizados com valores convertidos de forma apropriada.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Declarar variável privada ao módulo: &#039;&#039;&#039;real r1 = 22.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public real r2 = 7.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public auto r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Usar definição externa de variável pública: &#039;&#039;&#039;forward real r2&#039;&#039;&#039;&lt;br /&gt;
* Declarar função (nativa P6) definida externamente: &#039;&#039;&#039;forward int&amp;lt;int&amp;gt; factorial&#039;&#039;&#039;&lt;br /&gt;
* Declarar função definida noutra linguagem (e.g. em C): &#039;&#039;&#039;extern [void]&amp;lt;int&amp;gt; malloc&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inicialização ==&lt;br /&gt;
&lt;br /&gt;
Quando existe, é a designação do objecto que segue o símbolo &#039;&#039;&#039;=&#039;&#039;&#039;: inteiro, real, cadeia de caracteres, ou 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.&amp;lt;!-- A associação de valores funcionais a variáveis pode ser realizada quando os tipos forem covariantes. As cadeias de caracteres são (possivelmente) inicializadas com uma lista não nula de valores sem separadores.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A palavra &#039;&#039;&#039;auto&#039;&#039;&#039; pode ser usada em lugar do tipo para declarar uma variável. Quando usada, o tipo da variável é inferido a partir do valor inicial (nestes casos, o valor inicial é obrigatório).&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Inteiro (literal): &#039;&#039;&#039;int i = 3&#039;&#039;&#039;&lt;br /&gt;
* Inteiro (expressão): &#039;&#039;&#039;int i = j + 1&#039;&#039;&#039;&lt;br /&gt;
* Real (literal): &#039;&#039;&#039;real r = 3.2&#039;&#039;&#039;&lt;br /&gt;
* Real (expressão): &#039;&#039;&#039;real r = i - 2.5&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literal): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literais): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot; &amp;quot;mãe&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (literal): &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[real]]] p&amp;lt;/nowiki&amp;gt; = null&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (expressão): &#039;&#039;&#039;[int] p = q + 1&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;!--* Função:&lt;br /&gt;
 int&amp;lt;int&amp;gt; f1&lt;br /&gt;
 int&amp;lt;real&amp;gt; g1&lt;br /&gt;
 real&amp;lt;int&amp;gt; g2&lt;br /&gt;
 int&amp;lt;int&amp;gt; f2 = f1  // ok: mesmo tipo&lt;br /&gt;
 f2 = g1 // ok: tipos covariantes&lt;br /&gt;
 f2 = g2 // ERRADO&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Funções =&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Declaração ==&lt;br /&gt;
&lt;br /&gt;
As funções têm um nome que é também o endereço dessa função. O tipo de retorno de uma função que não produz valores de retorno é &#039;&#039;&#039;void&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
As funções que recebam argumentos devem indicá-los no cabeçalho. Funções sem argumentos definem um cabeçalho vazio. Os qualificadores de exportação/importação &#039;&#039;&#039;public&#039;&#039;&#039; ou &#039;&#039;&#039;forward&#039;&#039;&#039; (ver símbolos globais) podem ser aplicados às funções, mas não é possível aplicá-los às declarações dos argumentos de uma função. Não é possível especificar valores por omissão para os argumentos de uma função, nem para o valor de retorno.&lt;br /&gt;
&lt;br /&gt;
A declaração de um ponteiro para uma função (ou, de forma equivalente, do seu nome) é utilizada para caracterizar 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). &amp;lt;!--Caso a declaração tenha corpo, define-se uma nova função.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Invocação ==&lt;br /&gt;
&lt;br /&gt;
Uma função pode ser invocada através do seu nome. &amp;lt;!--ou de um ponteiro do tipo apropriado que refira essa função (ponteiro não nulo). O símbolo &#039;&#039;&#039;@&#039;&#039;&#039; pode ser usado dentro da própria função para efectuar uma invocação recursiva. Não é possível o uso de &#039;&#039;&#039;@&#039;&#039;&#039; no programa principal.--&amp;gt;&lt;br /&gt;
Se existirem argumentos, na invocação da função, o nome é 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 menos de conversões implícitas). A ordem dos parâmetros actuais deverá ser a mesma dos argumentos formais da função a ser invocada.&lt;br /&gt;
&lt;br /&gt;
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. Note que o retorno de entidades com dimensão superior a 64 bits deve fazer-se através da reserva de espaço para o retorno no chamador e passando um ponteiro para esse espaço como primeiro argumento do chamado.&lt;br /&gt;
&lt;br /&gt;
== Corpo ==&lt;br /&gt;
&lt;br /&gt;
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 de exportação (&#039;&#039;&#039;public&#039;&#039;&#039;) ou de importação (&#039;&#039;&#039;forward&#039;&#039;&#039; ou &#039;&#039;&#039;extern&#039;&#039;&#039;) (ver [[#Símbolos globais|símbolos globais]]) dentro do corpo de uma função.&lt;br /&gt;
&lt;br /&gt;
Uma instrução &#039;&#039;&#039;return&#039;&#039;&#039; causa a interrupção da função. O valor devolvido por uma função, através de expressão usada como argumento da instrução &#039;&#039;&#039;return&#039;&#039;&#039;, deve ser do tipo declarado no cabeçalho da função. Ver casos especiais acima.&lt;br /&gt;
&lt;br /&gt;
É um erro especificar um valor de retorno se a função for declarada como não retornando um valor (indicada como &#039;&#039;&#039;void&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Qualquer bloco (usado, por exemplo, numa instrução condicional ou de iteração) pode definir variáveis locais. &amp;lt;!--, cujos valores podem ser outras funções. Funções definidas dentro de um bloco não têm acesso às variáveis em contexto na função actual onde ocorrem.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Função principal e execução de programas ==&lt;br /&gt;
&lt;br /&gt;
Um programa é a sequência de instruções que seguem as declarações globais num ficheiro, delimitadas pelas palavras-chave &#039;&#039;&#039;begin&#039;&#039;&#039; e &#039;&#039;&#039;end&#039;&#039;&#039;. Esta sequência forma o que em algumas linguagens se chama a função principal. Os argumentos com que o programa foi chamado podem ser obtidos através de funções &#039;&#039;&#039;argc&#039;&#039;&#039; (devolve o número de argumentos); &#039;&#039;&#039;argv&#039;&#039;&#039; (devolve o n-ésimo argumento como uma cadeia de caracteres, com n&amp;gt;0); e &#039;&#039;&#039;envp&#039;&#039;&#039; (devolve a n-ésima variável de ambiente como uma cadeia de caracteres, com n&amp;gt;0). Apenas um dos módulos do programa pode definir a função principal, i.e., se existirem vários módulos, apenas um deles pode conter mais do que declarações de variáveis globais.&lt;br /&gt;
&lt;br /&gt;
 extern int&amp;lt;&amp;gt; argc&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; argv&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; envp&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
= Instruções =&lt;br /&gt;
&lt;br /&gt;
Excepto quando indicado, as instruções são executadas em sequência.&lt;br /&gt;
&lt;br /&gt;
== Blocos ==&lt;br /&gt;
&lt;br /&gt;
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 definir funções dentro de blocos, mas é possível declarar ponteiros de função locais.&lt;br /&gt;
&lt;br /&gt;
A visibilidade das variáveis é limitada ao bloco em que foram declaradas. As entidades declaradas podem ser directamente utilizadas em sub-blocos ou passadas como argumentos para funções chamadas dentro do bloco. Caso os identificadores usados para definir as variáveis locais já estejam a ser utilizados para definir outras entidades ao alcance do bloco, o novo identificador passa a referir uma nova entidade definida no bloco até que ele termine (a entidade previamente definida continua a existir, mas não pode ser directamente referida pelo seu nome). Esta regra é também válida relativamente a&lt;br /&gt;
argumentos de funções (ver corpo das funções).&lt;br /&gt;
&lt;br /&gt;
== Instrução condicional ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento semelhante ao da instrução &#039;&#039;&#039;if-else&#039;&#039;&#039; em C. As partes correspondentes a &#039;&#039;&#039;elif&#039;&#039;&#039; comportam-se como encadeamentos de instruções condicionais na parte &#039;&#039;&#039;else&#039;&#039;&#039; de um &#039;&#039;&#039;if-else&#039;&#039;&#039; à la C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de iteração ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento idêntico ao da instrução &#039;&#039;&#039;while&#039;&#039;&#039; em C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de terminação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;stop&#039;&#039;&#039; termina o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;break&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de continuação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;next&#039;&#039;&#039; reinicia o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;continue&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de retorno ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;return&#039;&#039;&#039;, se existir, é a última instrução do seu bloco. Ver comportamento na [[#Corpo|descrição do corpo de uma função]].&lt;br /&gt;
&lt;br /&gt;
== Expressões como instruções ==&lt;br /&gt;
&lt;br /&gt;
As expressões utilizadas como instruções são sempre avaliadas, mesmo que não produzam efeitos secundários.&lt;br /&gt;
&lt;br /&gt;
== Instruções de impressão ==&lt;br /&gt;
&lt;br /&gt;
As notações &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; podem ser utilizadas para apresentar valores na saída do programa. A primeira forma apresenta os valores sem mudar de linha; a segunda forma apresenta os valores mudando de linha depois de os apresentar a todos. Quando existe mais de uma expressão, as várias expressões são apresentadas sem separação. Valores numéricos (inteiros ou reais) são impressos em decimal. As cadeias de caracteres são impressas na codificação nativa. Ponteiros não podem ser impressos.&lt;br /&gt;
&lt;br /&gt;
= Expressões =&lt;br /&gt;
&lt;br /&gt;
Uma expressão é uma representação algébrica de uma quantidade: todas as expressões têm um tipo e devolvem um valor.&lt;br /&gt;
&lt;br /&gt;
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]].&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
 {|&lt;br /&gt;
| &#039;&#039;&#039;Tipo de Expressão&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operadores&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Associatividade&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operandos&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Semântica&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| primária&lt;br /&gt;
| &#039;&#039;&#039;( ) [ ]&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Parênteses curvos|parênteses curvos]], [[#Indexação|indexação]], [[#Reserva de memória|reserva de memória]]&lt;br /&gt;
|-&lt;br /&gt;
| unária&lt;br /&gt;
| &#039;&#039;&#039;+ - ?&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Identidade e simétrico|identidade e simétrico]], [[#Expressão de indicação de posição|indicação de posição]]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;não&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;~&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | não associativo&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: negação&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | multiplicativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;* / %&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | aditiva&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;+ -&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias: se envolverem ponteiros, calculam: (i) deslocamentos, i.e., um dos operandos deve ser do tipo ponteiro e o outro do tipo inteiro (binário de 32 bits); (ii) diferenças de ponteiros, i.e., apenas quando se aplica o operador &#039;&#039;&#039;-&#039;&#039;&#039; a dois ponteiros do mesmo tipo (o resultado é o número de objectos do tipo apontado entre eles, representado como um valor inteiro ternário de 64 bits). Se a memória não for contígua, o resultado é indefinido.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | comparativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt; &amp;gt; &amp;lt;= &amp;gt;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | igualdade&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;== !=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;e&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for falso.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;ou&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for verdadeiro.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | atribuição&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da direita para a esquerda&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | todos os tipos&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | O valor da expressão do lado direito do operador é guardado na posição indicada pelo &#039;&#039;left-value&#039;&#039; (operando esquerdo do operador). Podem ser atribuídos valores inteiros a &#039;&#039;left-values&#039;&#039; reais (conversão automática). Nos outros casos, ambos os tipos têm de concordar. O literal &#039;&#039;&#039;null&#039;&#039;&#039; é compatível com todos os tipos de ponteiros.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Expressões primitivas ==&lt;br /&gt;
&lt;br /&gt;
As [[#Literais|expressões literais]] e a [[#Invocação|invocação de funções]] foram definidas acima.&lt;br /&gt;
&lt;br /&gt;
=== Identificadores ===&lt;br /&gt;
&lt;br /&gt;
Um identificador é uma expressão se tiver sido declarado. Um identificador pode denotar uma variável.&lt;br /&gt;
&lt;br /&gt;
Um identificador é o caso mais simples de um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;, ou seja, uma entidade que pode ser utilizada no lado esquerdo (&#039;&#039;left&#039;&#039;) de uma atribuição.&lt;br /&gt;
&lt;br /&gt;
=== Leitura ===&lt;br /&gt;
&lt;br /&gt;
A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão indicada pela palavra-chave &#039;&#039;&#039;input&#039;&#039;&#039;, que devolve o valor lido, de acordo com o tipo esperado (inteiro ou real). Caso se use como argumento dos operadores de impressão ou noutras situações que permitam vários tipos (e.g. &#039;&#039;&#039;!&#039;&#039;&#039; ou &#039;&#039;&#039;!!&#039;&#039;&#039;), deve ser lido um inteiro.&lt;br /&gt;
&lt;br /&gt;
Exemplos:  &#039;&#039;&#039;a = input&#039;&#039;&#039; (leitura para &#039;&#039;&#039;a&#039;&#039;&#039;), &#039;&#039;&#039;f(input)&#039;&#039;&#039; (leitura para argumento de função), &#039;&#039;&#039;input!!&#039;&#039;&#039; (leitura e impressão).&lt;br /&gt;
&lt;br /&gt;
=== Parênteses curvos ===&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;left-value&#039;&#039; (ver também a [[#Indexação|expressão de indexação]]).&lt;br /&gt;
&amp;lt;!--=== Funções ===&lt;br /&gt;
&lt;br /&gt;
As funções (ponteiros ou o seu código: não confundir com chamadas a funções) podem ser usadas como expressões tipificadas como funções, i.e., ponteiros para funções (mesmo quando não se usa explicitamente um ponteiro).&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
 f1(int i) -&amp;gt; int { return i + 1; }&lt;br /&gt;
 f2(int i) -&amp;gt; int { return i * 2; }&lt;br /&gt;
&lt;br /&gt;
 g(int n, int&amp;lt;int&amp;gt; fun) -&amp;gt; int { return fun(n); }&lt;br /&gt;
 &lt;br /&gt;
 begin&lt;br /&gt;
   g(3, f1)!!  // escreve 4&lt;br /&gt;
   g(3, f2)!!  // escreve 6&lt;br /&gt;
 end&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expressões resultantes de avaliação de operadores ==&lt;br /&gt;
&lt;br /&gt;
=== Indexação de ponteiros ===&lt;br /&gt;
&lt;br /&gt;
A indexação de ponteiros devolve o valor de uma posição de memória indicada por um ponteiro. Consiste em uma expressão ponteiro seguida do índice entre parênteses rectos. O resultado de uma indexação de ponteiros é um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;. Não é possível indexar ponteiros que designem funções.&lt;br /&gt;
&lt;br /&gt;
Exemplo (acesso à posição 0 da zona de memória indicada por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;p[0]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Identidade e simétrico ===&lt;br /&gt;
&lt;br /&gt;
Os operadores identidade (&#039;&#039;&#039;+&#039;&#039;&#039;) e simétrico (&#039;&#039;&#039;-&#039;&#039;&#039;) aplicam-se a inteiros e reais. Têm o mesmo significado que em análogo às operações correspondentes em C, mas operam sobre grandezas ternárias.&lt;br /&gt;
&lt;br /&gt;
=== Reserva de memória ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Exemplo (reserva vector com 5 reais, apontados por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;[real] p = [5]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de indicação de posição ===&lt;br /&gt;
&lt;br /&gt;
O operador sufixo &#039;&#039;&#039;?&#039;&#039;&#039; aplica-se a &#039;&#039;left-values&#039;&#039;, retornando o endereço (com o tipo ponteiro) correspondente.&lt;br /&gt;
&lt;br /&gt;
Exemplo (indica o endereço de &#039;&#039;&#039;a&#039;&#039;&#039;): &#039;&#039;&#039;a?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de dimensão ===&lt;br /&gt;
&lt;br /&gt;
O operador &#039;&#039;&#039;sizeof&#039;&#039;&#039; tem um único argumento e aplica-se a expressões, retornando a dimensão correspondente em bytes.&lt;br /&gt;
&lt;br /&gt;
Exemplo: &#039;&#039;&#039;sizeof(a)&#039;&#039;&#039; (dimensão de &#039;&#039;&#039;a&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
= Exemplos e Testes =&lt;br /&gt;
&lt;br /&gt;
Os exemplos abaixo não são exaustivos e não ilustram todos os aspectos da linguagem.&lt;br /&gt;
&lt;br /&gt;
Estão ainda disponíveis outros [https://gitlab.rnl.tecnico.ulisboa.pt/leic-a-co26/eval/co26 pacotes de testes].&lt;br /&gt;
&lt;br /&gt;
O seguinte exemplo ilustra um programa com dois módulos: um que define a função &#039;&#039;&#039;factorial&#039;&#039;&#039; e outro que define a função principal.&lt;br /&gt;
&lt;br /&gt;
Definição da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;factorial.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
public factorial(int n) -&amp;gt; int {&lt;br /&gt;
  if (n &amp;gt; 1) &lt;br /&gt;
    return n * factorial(n - 1);&lt;br /&gt;
  else &lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exemplo da utilização da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;main.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
// external builtin functions (non-P6)&lt;br /&gt;
extern int&amp;lt;&amp;gt; argc;&lt;br /&gt;
extern string&amp;lt;int&amp;gt; argv;&lt;br /&gt;
extern int&amp;lt;string&amp;gt; atoi;&lt;br /&gt;
&lt;br /&gt;
// external user functions (P6)&lt;br /&gt;
forward int&amp;lt;int&amp;gt; factorial;&lt;br /&gt;
&lt;br /&gt;
// the main function&lt;br /&gt;
begin&lt;br /&gt;
  auto value = 1;&lt;br /&gt;
  &amp;quot;Teste para a função factorial.&amp;quot;!!&lt;br /&gt;
  if (argc() == 2) {&lt;br /&gt;
    string s = argv(1);&lt;br /&gt;
    value = atoi(s);&lt;br /&gt;
  }&lt;br /&gt;
  value, &amp;quot;! é &amp;quot;, factorial(value)!!&lt;br /&gt;
  return 0;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Como compilar:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
p6 --target asm factorial.p6&lt;br /&gt;
p6 --target asm main.p6&lt;br /&gt;
yasm -felf32 factorial.asm&lt;br /&gt;
yasm -felf32 main.asm&lt;br /&gt;
ld -melf_i386 -o main factorial.o main.o -lrts&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Omissões e Erros =&lt;br /&gt;
&lt;br /&gt;
Casos omissos e erros serão corrigidos em futuras versões do manual de referência.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026&amp;diff=17776</id>
		<title>Compiladores/Pautas 2025-2026</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026&amp;diff=17776"/>
		<updated>2026-05-15T13:20:27Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Pautas do Projecto (época normal) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Além dos resultados de avaliação, as páginas das pautas contêm também os critérios de avaliação e aprovação.&lt;br /&gt;
* {{PautaAberta}} indica avaliação em curso&lt;br /&gt;
* {{PautaFechada}} indica avaliação terminada (classificações definitivas)&lt;br /&gt;
* {{ProvaPorRealizar}} indica avaliação prevista&lt;br /&gt;
&lt;br /&gt;
== Pautas da Disciplina ==&lt;br /&gt;
&lt;br /&gt;
* [[Compiladores/Pautas 2025-2026/Pauta Global da Disciplina|Pauta Global da Disciplina]] -- próxima avaliação: (ver Fénix)&lt;br /&gt;
* {{PautaAberta}} [[Compiladores/Pautas 2025-2026/Pauta das Aulas Práticas|Pauta das Aulas Práticas]] (época nornal)&lt;br /&gt;
&lt;br /&gt;
== Pautas do Projecto (época normal) ==&lt;br /&gt;
&lt;br /&gt;
* {{PautaAberta}} [[Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega &amp;quot;zero&amp;quot;|Pauta do Projecto: Entrega &amp;quot;zero&amp;quot;]]&lt;br /&gt;
* {{PautaAberta}} [[Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega Intermédia|Pauta do Projecto: Entrega Intermédia]]&lt;br /&gt;
* {{ProvaPorRealizar}} [[Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega Final|Pauta do Projecto: Entrega Final]]&lt;br /&gt;
* [[Compiladores/Pautas 2025-2026/Pauta Global do Projecto|Pauta Global do Projecto]]&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores 2025-2026]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026/Pauta_do_Projecto:_Entrega_Interm%C3%A9dia&amp;diff=17775</id>
		<title>Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega Intermédia</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026/Pauta_do_Projecto:_Entrega_Interm%C3%A9dia&amp;diff=17775"/>
		<updated>2026-05-15T11:16:19Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Critérios de Avaliação */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
== Pauta ==&lt;br /&gt;
Aqui: https://bit.ly/co26-pautas (ver Fénix)&lt;br /&gt;
&lt;br /&gt;
== Prazo de Revisão ==&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;PAUTA EM ACTUALIZAÇÃO&amp;lt;/font&amp;gt;&#039;&#039;&#039;--&amp;gt;&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;PAUTA FECHADA&amp;lt;/font&amp;gt;&#039;&#039;&#039;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A entrega intermédia pode ser revista até à data da entrega final do projecto.&lt;br /&gt;
&lt;br /&gt;
== Critérios de Avaliação ==&lt;br /&gt;
&#039;&#039;&#039;LER COM ATENÇÃO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;A entrega intermédia é obrigatória.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A entrega intermédia vale 6 valores em 20.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A avaliação é realizada sobre a versão existente no repositório no final do prazo para a entrega intermédia. Projectos que não apresentem alterações relevantes relativamente ao conteúdo inicial do repositório ou relativamente à entrega inicial não serão considerados.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A avaliação da entrega intermédia considera a execução de intervenções em várias regiões do código do compilador em desenvolvimento, assim como a gestão do projecto correspondente.&lt;br /&gt;
&lt;br /&gt;
Advertem-se os alunos sobre a consulta de colegas de anos anteriores. Estas consultas podem ser positivas, mas comportam algum risco, pois o processo e critérios de avaliação podem ter mudado. Além disso, a proficiência do colega pode majorar negativamente o resultado da avaliação em curso. Não são admitidas quaisquer justificações com base na história da disciplina. De forma semelhante, a reciclagem de código de compiladores exemplo deve ser feita criteriosamente, por forma a evitar inclusão de código errado ou inútil.&lt;br /&gt;
&lt;br /&gt;
Estas condições são aplicáveis à data da entrega intermédia.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;Em caso de dúvidas suscitadas por qualquer elemento neste texto, no projecto, ou na disciplina em geral, os alunos são fortemente encorajados a consultar o corpo docente.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #BDDD8D;&amp;quot; | &amp;lt;font color=&amp;quot;forestgreen&amp;quot;&amp;gt;&#039;&#039;&#039;VALORAÇÕES&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Existem &#039;&#039;&#039;6 valores&#039;&#039;&#039; (dos 20 disponíveis para o projecto) associados a esta entrega:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;gestão do projecto: 1 valor&#039;&#039;&#039;&lt;br /&gt;
** projecto com a estrutura correcta no repositório: &#039;&#039;&#039;0.5 valores&#039;&#039;&#039; (i.e., código que não apresente a estrutura canónica de um compilador desenvolvido com a CDK é considerado sem a estrutura correcta -- consultar estas páginas sobre o desenvolvimento do projecto com base no repositório)&lt;br /&gt;
** projecto compila e produz compilador &amp;quot;p6&amp;quot; (&amp;quot;p6&amp;quot;, com letras minúsculas: variações correspondem a &amp;quot;não compilação&amp;quot;): &#039;&#039;&#039;0.5 valores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Se o projecto compilar&#039;&#039;&#039;, poderão ser atribuídos mais 5 valores (desenvolvimento do compilador), distribuídos como se segue:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Flex (completo): 1.5 valores&#039;&#039;&#039;&lt;br /&gt;
** Tokens correspondentes aos símbolos e palavras-chave (simples ajuste do Simple/Tritak)&lt;br /&gt;
** Identificadores (simples ajuste do Simple/Tritak)&lt;br /&gt;
** Inteiros (a base 10 já está implementada no Simple/Tritak)&lt;br /&gt;
** Reais (extensão dos inteiros)&lt;br /&gt;
** Strings (extensão do Simple/Tritak)&lt;br /&gt;
** O Flex deve retornar os tokens ao byacc (sobre DEBUG, ver abaixo) -- o não retorno de tokens penaliza fortemente toda a componente Flex (ver penalizações)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Bison (completo): 1 valor&#039;&#039;&#039;&lt;br /&gt;
** Regras correspondentes a literais de reais e strings (simples extensão do Simple/Tritak)&lt;br /&gt;
** Regras correspondentes a ciclos, etc. (simples extensão e adaptação do Simple/Tritak)&lt;br /&gt;
** Regras correspondentes a declarações de variáveis&lt;br /&gt;
** Regras correspondentes a declarações/definições de funções&lt;br /&gt;
** As acções correspondentes às regras definidas no Bison devem estar implementadas (simples criação de nós) -- a não implementação corresponde a penalizações (var abaixo)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nós (nodes) (completo): 1 valor&#039;&#039;&#039;&lt;br /&gt;
** Todos os nós necessários para a linguagem (utilizados na especificação Bison e em passos subsequentes) devem ser criados&lt;br /&gt;
** A não criação de nós motivada pela ausência de definição de acções no Bison é penalizada (ver abaixo)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Semântica (visitors) (&#039;&#039;&#039;xml_writer&#039;&#039;&#039; completo; &#039;&#039;&#039;postfix_writer&#039;&#039;&#039; ver a seguir): 1.5 valores&#039;&#039;&#039;&lt;br /&gt;
** O &amp;quot;visitor&amp;quot; &#039;&#039;&#039;xml_writer&#039;&#039;&#039; deve estar completamente implementado (ver também DEBUG abaixo)&lt;br /&gt;
** O &amp;quot;visitor&amp;quot; &#039;&#039;&#039;type_checker&#039;&#039;&#039; deve ter todos os métodos (correspondentes aos nós, tal como o &#039;&#039;&#039;xml_writer&#039;&#039;&#039;), embora alguns possam estar ainda vazios (i.e., podem não executar qualquer acção)&lt;br /&gt;
** O &amp;quot;visitor&amp;quot; &#039;&#039;&#039;postfix_writer&#039;&#039;&#039; deve ter todos os métodos (correspondentes aos nós, tal como o &#039;&#039;&#039;xml_writer&#039;&#039;&#039;), embora alguns possam estar ainda vazios (i.e., podem não executar qualquer acção)&lt;br /&gt;
** Métodos correspondentes a acções semelhantes às existentes devem ser modelados nos existentes (mesmo que não modificados numa primeira instância)&lt;br /&gt;
** A presença de implementações de semântica no &#039;&#039;&#039;postfix_writer&#039;&#039;&#039; (tabela de símbolos, validação de tipos, etc.) não é penalizada, mas não será avaliada nesta entrega&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #FFCC99;&amp;quot; | &amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;PENALIZAÇÕES&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Existem penalizações relativas à (deficiente) execução do projecto. &lt;br /&gt;
&lt;br /&gt;
São considerados os seguintes aspectos preliminares:&lt;br /&gt;
&lt;br /&gt;
# A linguagem do projecto contém a linguagem Simple, pelo que não há razão para não utilizar completamente o compilador Simple, eventualmente com pequenas alterações (including a passagem de binário para ternário).&lt;br /&gt;
# A semântica da linguagem do projecto contém a da linguagem Simple, pelo que a implementação de alguns aspectos da linguagem do projecto não requer qualquer reimplementação relativamente ao Simple.&lt;br /&gt;
# O compilador Simple foi fornecido completamente funcional, assim como a versão inicial do compilador do projecto no respositório (igual ao Simple e apenas alterado para ter o nome apropriado).&lt;br /&gt;
# A criação de novos nós não apresenta quaisquer dificuldades (são classes muito simples)&lt;br /&gt;
# O código dos métodos do visitor &#039;&#039;&#039;xml_writer&#039;&#039;&#039; corresponde a uma simples impressão dos atributos dos nós, através de uma travessia da árvore que formam e que os contém.&lt;br /&gt;
# O compilador é obrigatoriamente desenvolvido em C++.&lt;br /&gt;
&lt;br /&gt;
Considerando os aspectos 1. a 6., são aplicadas as seguintes penalizações:&lt;br /&gt;
&lt;br /&gt;
* Destruição de funcionalidade do compilador Simple sem substituição por funcionalidade equivalente do compilador do projecto: &#039;&#039;&#039;4 valores&#039;&#039;&#039;&lt;br /&gt;
Não definição dos nós para regras Bison em avaliação (ver acima) ou não utilização de nós definidos para a escrita dessas acções: &#039;&#039;&#039;2 valores&#039;&#039;&#039;&lt;br /&gt;
* A utilização de funções e estruturas C, quando existem alternativas directas C++ (malloc em lugar de new, por exemplo; strcmp, etc. em lugar da classe std::string; e outras) terá uma &#039;&#039;&#039;penalização máxima de 1 valor&#039;&#039;&#039;&lt;br /&gt;
* Não utilização de qualquer material obrigatório: &#039;&#039;&#039;6 valores (e considera-se projecto não realizado)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== DEBUG ===&lt;br /&gt;
&lt;br /&gt;
O despiste de problemas em especificações Flex pode ser realizado de forma simples utilizando os métodos descritos em [[The Flex Lexical Analyzer#How to Debug a Flex Specification|How to Debug a Flex Specification]].&lt;br /&gt;
&lt;br /&gt;
O visitor &#039;&#039;&#039;xml_writer&#039;&#039;&#039; foi concebido para produzir uma representação textual hierárquica (árvore XML) correspondente ao programa em compilação. &lt;br /&gt;
É muito útil para inspeccionar a construção da árvore de nós por parte do Bison, permitindo, inclusivamente, a apresentação gráfica.&lt;br /&gt;
&lt;br /&gt;
== Legenda ==&lt;br /&gt;
As questões relativas às colunas &amp;quot;Problemas&amp;quot; devem ser resolvidas quanto antes (nos horários de dúvidas ou, sendo possível, por correio electrónico).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Problemas na análise lexical&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
* .* - uso indevido do padrão&lt;br /&gt;
* chars - definição indevida (não existem na linguagem)&lt;br /&gt;
* comments - problemas com comentários (em excesso ou em falta)&lt;br /&gt;
* doubles - problemas com vírgula flutuante (definições incompletas)&lt;br /&gt;
&amp;lt;!--* indents - problems com indentação--&amp;gt;&lt;br /&gt;
* ids - problems com identificadores &lt;br /&gt;
* int - problemas com inteiros (definições incompletas ou excessivas)&lt;br /&gt;
* keywords - problemas com palavras-chave (a mais ou a menos)&lt;br /&gt;
&amp;lt;!--* ops - problemas com operadores e afins--&amp;gt;&lt;br /&gt;
* (bad) patterns - problemas genéricos com escrita de padrões lexicais&lt;br /&gt;
* string - problemas na definição de strings (composição, concatenação indevida, etc.)&lt;br /&gt;
* [outros] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Problemas na análise sintáctica&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
* conflicts - conflitos no analisador LALR(1) (não avaliado nesta entrega)&lt;br /&gt;
* decls - problemas nas declarações (e.g. mistura com expressões ou com instruções)&lt;br /&gt;
* empty rules - regras sem semântica associada &lt;br /&gt;
* exprs - problemas nas expressões (em falta ou com inclusão de casos errados)&lt;br /&gt;
* calls - problemas nas chamadas a funções (e.g. não estão definidos como expressões)&lt;br /&gt;
* funcs - problemas (vários) nas &amp;lt;!--declarações/--&amp;gt;definições de funções&lt;br /&gt;
* lvals - problemas na definição de left-values (e.g. ausência de definições ou incompletas)&lt;br /&gt;
* precs - problemas na definição de precedências (tipicamente, em excesso, deficientes, ou sem correspondência com o manual)&lt;br /&gt;
* precs* - problemas graves na definição de precedências (tipicamente, em excesso, deficientes, ou sem correspondência com o manual)&lt;br /&gt;
* tokens - problemas na definição de tokens (tipicamente, em excesso ou sem correspondência com o manual)&lt;br /&gt;
* read - problemas na definição da expressão de leitura (verificar manual de referência)&lt;br /&gt;
* semantics - problemas na definição de acções semânticas&lt;br /&gt;
* (simple) - contém apenas a definição original (linguagem Simple)&lt;br /&gt;
* strings - problemas na definção de cadeias de caracteres&lt;br /&gt;
* syntax - problemas na definição da gramática ou na semântica (nó) correspondente (verificar manual de referência)&lt;br /&gt;
* start - problemas na definição da raiz da árvore sintáctica (compiler-&amp;gt;ast(...))&lt;br /&gt;
* [outras anotações] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Problemas na análise semântica e na geração de código (nós e XML)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Nos nós:&lt;br /&gt;
&amp;lt;!--* lvals - problemas na definição ou uso de left-values&lt;br /&gt;
* decls - problemas na definição de declarações/definições de funções/variáveis&lt;br /&gt;
* read_node - uso de left-value no read_node (não é uma atribuição, pelo que não tem left-values); ou derivação de basic_node (mas deve ser uma expressão); ou derivação de unary_expression (mas não tem argumentos); ou remoção do nó--&amp;gt;&lt;br /&gt;
* [outros nós] - nós com problemas (nós excedentários ou em falta ou com problemas na definição)&lt;br /&gt;
* [outras anotações] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
No visitor &#039;&#039;&#039;xml_writer&#039;&#039;&#039;:&lt;br /&gt;
* ast - o método &amp;quot;ast&amp;quot; do compilador não foi chamado no parser (.y), pelo que a AST está indefinida&lt;br /&gt;
* empty - métodos vazios ou funcionalmente vazios&lt;br /&gt;
* (incomp) - código incompleto&lt;br /&gt;
* [outras anotações] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores 2025-2026]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026/Pauta_do_Projecto:_Entrega_Interm%C3%A9dia&amp;diff=17774</id>
		<title>Compiladores/Pautas 2025-2026/Pauta do Projecto: Entrega Intermédia</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Pautas_2025-2026/Pauta_do_Projecto:_Entrega_Interm%C3%A9dia&amp;diff=17774"/>
		<updated>2026-05-15T11:14:49Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Critérios de Avaliação */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
== Pauta ==&lt;br /&gt;
Aqui: https://bit.ly/co26-pautas (ver Fénix)&lt;br /&gt;
&lt;br /&gt;
== Prazo de Revisão ==&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;PAUTA EM ACTUALIZAÇÃO&amp;lt;/font&amp;gt;&#039;&#039;&#039;--&amp;gt;&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;PAUTA FECHADA&amp;lt;/font&amp;gt;&#039;&#039;&#039;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A entrega intermédia pode ser revista até à data da entrega final do projecto.&lt;br /&gt;
&lt;br /&gt;
== Critérios de Avaliação ==&lt;br /&gt;
&#039;&#039;&#039;LER COM ATENÇÃO&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;A entrega intermédia é obrigatória.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A entrega intermédia vale 6 valores em 20.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A avaliação é realizada sobre a versão existente no repositório no final do prazo para a entrega intermédia. Projectos que não apresentem alterações relevantes relativamente ao conteúdo inicial do repositório ou relativamente à entrega inicial não serão considerados.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A avaliação da entrega intermédia considera a execução de intervenções em várias regiões do código do compilador em desenvolvimento, assim como a gestão do projecto correspondente.&lt;br /&gt;
&lt;br /&gt;
Advertem-se os alunos sobre a consulta de colegas de anos anteriores. Estas consultas podem ser positivas, mas comportam algum risco, pois o processo e critérios de avaliação podem ter mudado. Além disso, a proficiência do colega pode majorar negativamente o resultado da avaliação em curso. Não são admitidas quaisquer justificações com base na história da disciplina. De forma semelhante, a reciclagem de código de compiladores exemplo deve ser feita criteriosamente, por forma a evitar inclusão de código errado ou inútil.&lt;br /&gt;
&lt;br /&gt;
Estas condições são aplicáveis à data da entrega intermédia.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;Em caso de dúvidas suscitadas por qualquer elemento neste texto, no projecto, ou na disciplina em geral, os alunos são fortemente encorajados a consultar o corpo docente.&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #BDDD8D;&amp;quot; | &amp;lt;font color=&amp;quot;forestgreen&amp;quot;&amp;gt;&#039;&#039;&#039;VALORAÇÕES&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Existem &#039;&#039;&#039;6 valores&#039;&#039;&#039; (dos 20 disponíveis para o projecto) associados a esta entrega:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;gestão do projecto: 1 valor&#039;&#039;&#039;&lt;br /&gt;
** projecto com a estrutura correcta no repositório: &#039;&#039;&#039;0.5 valores&#039;&#039;&#039; (i.e., código que não apresente a estrutura canónica de um compilador desenvolvido com a CDK é considerado sem a estrutura correcta -- consultar estas páginas sobre o desenvolvimento do projecto com base no repositório)&lt;br /&gt;
** projecto compila e produz compilador &amp;quot;p6&amp;quot; (&amp;quot;p6&amp;quot;, com letras minúsculas: variações correspondem a &amp;quot;não compilação&amp;quot;): &#039;&#039;&#039;0.5 valores&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Se o projecto compilar&#039;&#039;&#039;, poderão ser atribuídos mais 5 valores (desenvolvimento do compilador), distribuídos como se segue:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Flex (completo): 1.5 valores&#039;&#039;&#039;&lt;br /&gt;
** Tokens correspondentes aos símbolos e palavras-chave (simples ajuste do Simple)&lt;br /&gt;
** Identificadores (simples ajuste do Simple/Tritak)&lt;br /&gt;
** Inteiros (a base 10 já está implementada no Simple/Tritak)&lt;br /&gt;
** Reais (extensão dos inteiros)&lt;br /&gt;
** Strings (extensão do Simple/Tritak)&lt;br /&gt;
** O Flex deve retornar os tokens ao byacc (sobre DEBUG, ver abaixo) -- o não retorno de tokens penaliza fortemente toda a componente Flex (ver penalizações)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Bison (completo): 1 valor&#039;&#039;&#039;&lt;br /&gt;
** Regras correspondentes a literais de reais e strings (simples extensão do Simple/Tritak)&lt;br /&gt;
** Regras correspondentes a ciclos, etc. (simples extensão e adaptação do Simple/Tritak)&lt;br /&gt;
** Regras correspondentes a declarações de variáveis&lt;br /&gt;
** Regras correspondentes a declarações/definições de funções&lt;br /&gt;
** As acções correspondentes às regras definidas no Bison devem estar implementadas (simples criação de nós) -- a não implementação corresponde a penalizações (var abaixo)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nós (nodes) (completo): 1 valor&#039;&#039;&#039;&lt;br /&gt;
** Todos os nós necessários para a linguagem (utilizados na especificação Bison e em passos subsequentes) devem ser criados&lt;br /&gt;
** A não criação de nós motivada pela ausência de definição de acções no Bison é penalizada (ver abaixo)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Semântica (visitors) (&#039;&#039;&#039;xml_writer&#039;&#039;&#039; completo; &#039;&#039;&#039;postfix_writer&#039;&#039;&#039; ver a seguir): 1.5 valores&#039;&#039;&#039;&lt;br /&gt;
** O &amp;quot;visitor&amp;quot; &#039;&#039;&#039;xml_writer&#039;&#039;&#039; deve estar completamente implementado (ver também DEBUG abaixo)&lt;br /&gt;
** O &amp;quot;visitor&amp;quot; &#039;&#039;&#039;type_checker&#039;&#039;&#039; deve ter todos os métodos (correspondentes aos nós, tal como o &#039;&#039;&#039;xml_writer&#039;&#039;&#039;), embora alguns possam estar ainda vazios (i.e., podem não executar qualquer acção)&lt;br /&gt;
** O &amp;quot;visitor&amp;quot; &#039;&#039;&#039;postfix_writer&#039;&#039;&#039; deve ter todos os métodos (correspondentes aos nós, tal como o &#039;&#039;&#039;xml_writer&#039;&#039;&#039;), embora alguns possam estar ainda vazios (i.e., podem não executar qualquer acção)&lt;br /&gt;
** Métodos correspondentes a acções semelhantes às existentes devem ser modelados nos existentes (mesmo que não modificados numa primeira instância)&lt;br /&gt;
** A presença de implementações de semântica no &#039;&#039;&#039;postfix_writer&#039;&#039;&#039; (tabela de símbolos, validação de tipos, etc.) não é penalizada, mas não será avaliada nesta entrega&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #FFCC99;&amp;quot; | &amp;lt;font color=&amp;quot;brown&amp;quot;&amp;gt;&#039;&#039;&#039;PENALIZAÇÕES&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Existem penalizações relativas à (deficiente) execução do projecto. &lt;br /&gt;
&lt;br /&gt;
São considerados os seguintes aspectos preliminares:&lt;br /&gt;
&lt;br /&gt;
# A linguagem do projecto contém a linguagem Simple, pelo que não há razão para não utilizar completamente o compilador Simple, eventualmente com pequenas alterações (including a passagem de binário para ternário).&lt;br /&gt;
# A semântica da linguagem do projecto contém a da linguagem Simple, pelo que a implementação de alguns aspectos da linguagem do projecto não requer qualquer reimplementação relativamente ao Simple.&lt;br /&gt;
# O compilador Simple foi fornecido completamente funcional, assim como a versão inicial do compilador do projecto no respositório (igual ao Simple e apenas alterado para ter o nome apropriado).&lt;br /&gt;
# A criação de novos nós não apresenta quaisquer dificuldades (são classes muito simples)&lt;br /&gt;
# O código dos métodos do visitor &#039;&#039;&#039;xml_writer&#039;&#039;&#039; corresponde a uma simples impressão dos atributos dos nós, através de uma travessia da árvore que formam e que os contém.&lt;br /&gt;
# O compilador é obrigatoriamente desenvolvido em C++.&lt;br /&gt;
&lt;br /&gt;
Considerando os aspectos 1. a 6., são aplicadas as seguintes penalizações:&lt;br /&gt;
&lt;br /&gt;
* Destruição de funcionalidade do compilador Simple sem substituição por funcionalidade equivalente do compilador do projecto: &#039;&#039;&#039;4 valores&#039;&#039;&#039;&lt;br /&gt;
Não definição dos nós para regras Bison em avaliação (ver acima) ou não utilização de nós definidos para a escrita dessas acções: &#039;&#039;&#039;2 valores&#039;&#039;&#039;&lt;br /&gt;
* A utilização de funções e estruturas C, quando existem alternativas directas C++ (malloc em lugar de new, por exemplo; strcmp, etc. em lugar da classe std::string; e outras) terá uma &#039;&#039;&#039;penalização máxima de 1 valor&#039;&#039;&#039;&lt;br /&gt;
* Não utilização de qualquer material obrigatório: &#039;&#039;&#039;6 valores (e considera-se projecto não realizado)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== DEBUG ===&lt;br /&gt;
&lt;br /&gt;
O despiste de problemas em especificações Flex pode ser realizado de forma simples utilizando os métodos descritos em [[The Flex Lexical Analyzer#How to Debug a Flex Specification|How to Debug a Flex Specification]].&lt;br /&gt;
&lt;br /&gt;
O visitor &#039;&#039;&#039;xml_writer&#039;&#039;&#039; foi concebido para produzir uma representação textual hierárquica (árvore XML) correspondente ao programa em compilação. &lt;br /&gt;
É muito útil para inspeccionar a construção da árvore de nós por parte do Bison, permitindo, inclusivamente, a apresentação gráfica.&lt;br /&gt;
&lt;br /&gt;
== Legenda ==&lt;br /&gt;
As questões relativas às colunas &amp;quot;Problemas&amp;quot; devem ser resolvidas quanto antes (nos horários de dúvidas ou, sendo possível, por correio electrónico).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Problemas na análise lexical&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
* .* - uso indevido do padrão&lt;br /&gt;
* chars - definição indevida (não existem na linguagem)&lt;br /&gt;
* comments - problemas com comentários (em excesso ou em falta)&lt;br /&gt;
* doubles - problemas com vírgula flutuante (definições incompletas)&lt;br /&gt;
&amp;lt;!--* indents - problems com indentação--&amp;gt;&lt;br /&gt;
* ids - problems com identificadores &lt;br /&gt;
* int - problemas com inteiros (definições incompletas ou excessivas)&lt;br /&gt;
* keywords - problemas com palavras-chave (a mais ou a menos)&lt;br /&gt;
&amp;lt;!--* ops - problemas com operadores e afins--&amp;gt;&lt;br /&gt;
* (bad) patterns - problemas genéricos com escrita de padrões lexicais&lt;br /&gt;
* string - problemas na definição de strings (composição, concatenação indevida, etc.)&lt;br /&gt;
* [outros] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Problemas na análise sintáctica&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
* conflicts - conflitos no analisador LALR(1) (não avaliado nesta entrega)&lt;br /&gt;
* decls - problemas nas declarações (e.g. mistura com expressões ou com instruções)&lt;br /&gt;
* empty rules - regras sem semântica associada &lt;br /&gt;
* exprs - problemas nas expressões (em falta ou com inclusão de casos errados)&lt;br /&gt;
* calls - problemas nas chamadas a funções (e.g. não estão definidos como expressões)&lt;br /&gt;
* funcs - problemas (vários) nas &amp;lt;!--declarações/--&amp;gt;definições de funções&lt;br /&gt;
* lvals - problemas na definição de left-values (e.g. ausência de definições ou incompletas)&lt;br /&gt;
* precs - problemas na definição de precedências (tipicamente, em excesso, deficientes, ou sem correspondência com o manual)&lt;br /&gt;
* precs* - problemas graves na definição de precedências (tipicamente, em excesso, deficientes, ou sem correspondência com o manual)&lt;br /&gt;
* tokens - problemas na definição de tokens (tipicamente, em excesso ou sem correspondência com o manual)&lt;br /&gt;
* read - problemas na definição da expressão de leitura (verificar manual de referência)&lt;br /&gt;
* semantics - problemas na definição de acções semânticas&lt;br /&gt;
* (simple) - contém apenas a definição original (linguagem Simple)&lt;br /&gt;
* strings - problemas na definção de cadeias de caracteres&lt;br /&gt;
* syntax - problemas na definição da gramática ou na semântica (nó) correspondente (verificar manual de referência)&lt;br /&gt;
* start - problemas na definição da raiz da árvore sintáctica (compiler-&amp;gt;ast(...))&lt;br /&gt;
* [outras anotações] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;mw-collapsible mw-collapsed wikitable&amp;quot; align=&amp;quot;right&amp;quot; style=&amp;quot;border-style: solid; border-width: 1px; border-color: #bbbbaa; background: #f7f8ff;&amp;quot;&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; border-style: solid; border-width: 0px; border-bottom-width: 0px; border-color: #bbbbaa;  background: #d7d8ed;&amp;quot; | &#039;&#039;&#039;Problemas na análise semântica e na geração de código (nós e XML)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;padding-left:10px; padding-right:10px; font-weight: normal; border-style: solid; border-width: 1px; border-color: #bbbbaa; &amp;quot; | &lt;br /&gt;
&lt;br /&gt;
Nos nós:&lt;br /&gt;
&amp;lt;!--* lvals - problemas na definição ou uso de left-values&lt;br /&gt;
* decls - problemas na definição de declarações/definições de funções/variáveis&lt;br /&gt;
* read_node - uso de left-value no read_node (não é uma atribuição, pelo que não tem left-values); ou derivação de basic_node (mas deve ser uma expressão); ou derivação de unary_expression (mas não tem argumentos); ou remoção do nó--&amp;gt;&lt;br /&gt;
* [outros nós] - nós com problemas (nós excedentários ou em falta ou com problemas na definição)&lt;br /&gt;
* [outras anotações] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
No visitor &#039;&#039;&#039;xml_writer&#039;&#039;&#039;:&lt;br /&gt;
* ast - o método &amp;quot;ast&amp;quot; do compilador não foi chamado no parser (.y), pelo que a AST está indefinida&lt;br /&gt;
* empty - métodos vazios ou funcionalmente vazios&lt;br /&gt;
* (incomp) - código incompleto&lt;br /&gt;
* [outras anotações] - casos específicos (contactar professor responsável)&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores 2025-2026]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17773</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17773"/>
		<updated>2026-05-14T17:36:16Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17772</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17772"/>
		<updated>2026-05-14T17:35:57Z</updated>

		<summary type="html">&lt;p&gt;Root: /* The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17771</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17771"/>
		<updated>2026-05-14T17:35:44Z</updated>

		<summary type="html">&lt;p&gt;Root: /* The ASSERT_UNSPEC macro */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17770</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17770"/>
		<updated>2026-05-14T17:35:24Z</updated>

		<summary type="html">&lt;p&gt;Root: /* The C code generator */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17769</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17769"/>
		<updated>2026-05-14T17:35:10Z</updated>

		<summary type="html">&lt;p&gt;Root: /* The type checking visitor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17768</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17768"/>
		<updated>2026-05-14T17:34:54Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Symbol representation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17767</id>
		<title>Semantic Analysis/The Tiny language: semantic analysis example and C generation</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis/The_Tiny_language:_semantic_analysis_example_and_C_generation&amp;diff=17767"/>
		<updated>2026-05-14T17:34:26Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Gramática e Criação de Nós da Árvore Sintáctica Abstracta */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
Considere a seguinte gramárica (ε representa a produção nula), onde os operadores &#039;&#039;&#039;tWRITE&#039;&#039;&#039; (não associativo), &#039;&#039;&#039;=&#039;&#039;&#039; (associativo à direita) e &#039;&#039;&#039;+&#039;&#039;&#039; (associativo à esquerda) têm precedências crescentes.&lt;br /&gt;
&lt;br /&gt;
O primeiro objectivo é escrever, utilizando as classes disponibilizadas na CDK (subclasses de cdk::basic_node), uma especificação YACC para a gramática dada, contendo as acções semânticas que permitem construir a árvore sintáctica.&lt;br /&gt;
&lt;br /&gt;
O segundo objectivo é escrever os métodos de o tradutor para C (padrão de desenho Visitor) a árvore sintáctica anteriormente obtida. Esta tradução implica que os símbolos encontrados sejam recordados, para verificar futuras utilizações. Para tal, a classe &#039;&#039;&#039;tiny::symbol&#039;&#039;&#039; (que representa cada símbolo; esquematizado aqui e que se baseia no símbolo do compilador Simple) e a classe &#039;&#039;&#039;cdk::symbol_table&#039;&#039;&#039; serão utilizadas.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
prog  → decls exprs &#039;.&#039; &lt;br /&gt;
decls → ε | decls decl &#039;;&#039; &lt;br /&gt;
decl  → tINT tID | tSTR tID init &lt;br /&gt;
init  → ε | &#039;=&#039; tSTRING &lt;br /&gt;
exprs → expr | exprs &#039;,&#039; expr &lt;br /&gt;
expr  → tINTEGER | tID | tID &#039;=&#039; expr | expr &#039;+&#039; expr | tWRITE expr &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gramática e Criação de Nós da Árvore Sintáctica Abstracta ==&lt;br /&gt;
&lt;br /&gt;
In the answer to this exercise, we will consider the node tree defined as shown below (in a YACC-like syntax). Note that careful attention must be given to the choices between &#039;&#039;&#039;cdk::nil_node&#039;&#039;&#039; nodes and &#039;&#039;&#039;nullptr&#039;&#039;&#039; (null pointers) (these can be tested for performing special/exceptional actions, while Nil nodes are more useful when tests are undesirable and uniform behavior on the part of the code generator is desired).&lt;br /&gt;
&lt;br /&gt;
We follow the same nomenclature used in the Simple compiler: &#039;&#039;&#039;LINE&#039;&#039;&#039; is a macro corresponding to the source line and all nodes are either CDK nodes or derived from them (as in Simple).&lt;br /&gt;
&lt;br /&gt;
Completing (and, possibly, correcting) the following code, so that it runs, is left as an exercise.&lt;br /&gt;
{{CollapsedCode|File tiny.y|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
%{&lt;br /&gt;
#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;quot;ast/all.h&amp;quot;&lt;br /&gt;
%}&lt;br /&gt;
%parse-param {std::shared_ptr&amp;lt;cdk::compiler&amp;gt; compiler}&lt;br /&gt;
%union {&lt;br /&gt;
  //--- don&#039;t change *any* of these: if you do, you&#039;ll break the compiler.&lt;br /&gt;
  YYSTYPE() : type(cdk::primitive_type::create(0, cdk::TYPE_VOID)) {}&lt;br /&gt;
  ~YYSTYPE() {}&lt;br /&gt;
  YYSTYPE(const YYSTYPE &amp;amp;other) { *this = other; }&lt;br /&gt;
  YYSTYPE&amp;amp; operator=(const YYSTYPE &amp;amp;other) { type = other.type; return *this; }&lt;br /&gt;
  std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type;        /* expression type */&lt;br /&gt;
  //-- don&#039;t change *any* of these --- END!&lt;br /&gt;
&lt;br /&gt;
  int i;&lt;br /&gt;
  std::string *s;&lt;br /&gt;
  cdk::basic_node *n;&lt;br /&gt;
  cdk::expression_node *e;&lt;br /&gt;
}  &lt;br /&gt;
%token tINT tSTR tWRITE&lt;br /&gt;
%token&amp;lt;i&amp;gt; tINTEGER&lt;br /&gt;
%token&amp;lt;s&amp;gt; tID tSTRING&lt;br /&gt;
%type&amp;lt;e&amp;gt; expr init&lt;br /&gt;
%type&amp;lt;n&amp;gt; prog decls exprs decl&lt;br /&gt;
%%&lt;br /&gt;
prog: decls exprs &#039;.&#039; { $$ = new program_node(LINE, $1, $2); }&lt;br /&gt;
&lt;br /&gt;
decls: /* empty */    { $$ = new cdk::nil_node(LINE); }&lt;br /&gt;
     | decls decl &#039;;&#039; { $$ = new cdk::sequence_node(LINE, $2, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
decl: tINT tID      {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_INT), *$2, nullptr);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    | tSTR tID init {&lt;br /&gt;
        $$ = new declaration_node(LINE, cdk::primitive_type::create(4, cdk::TYPE_STRING), *$2, $3);&lt;br /&gt;
        delete $2;&lt;br /&gt;
    }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
init: /* empty */  { $$ = nullptr; /* must match the last argument in declaration_node */ }&lt;br /&gt;
    | &#039;=&#039; tSTRING  { $$ = new cdk::string_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&lt;br /&gt;
exprs: expr             { $$ = new cdk::sequence_node(LINE, $1); }&lt;br /&gt;
     | exprs &#039;,&#039; expr   { $$ = new cdk::sequence_node(LINE, $3, $1); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
expr: tINTEGER           { $$ = new cdk::integer_node(LINE, $1); }&lt;br /&gt;
    | tID                { $$ = new cdk::rvalue_node(LINE, new cdk::variable_node(LINE, *$1)); delete $1; }&lt;br /&gt;
    | tID &#039;=&#039; expr       { $$ = new cdk::assignment_node(LINE, new cdk::variable_node(LINE, *$1), $3); delete $1; }&lt;br /&gt;
    | expr &#039;+&#039; expr      { $$ = new cdk::add_node(LINE, $1, $3); }&lt;br /&gt;
    | tWRITE expr        { $$ = new write_node(LINE, $2); }&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
In this code we assume that each declaration node contains two attributes: an integer, representing the declaration&#039;s type; a node, representing the identifier being declared; and an optional expression (&#039;&#039;&#039;nullptr&#039;&#039;&#039; if that is the case), representing the initial value of the variable being declared. Likewise, assignment nodes have two children: an identifier, corresponding to the left-value; and the expression to be assigned. Write nodes have a single child (the expression to be printed) (note that, in this simple grammar, write nodes are also integer expressions). The program node (the main node) has two children: a node containing declarations and another containing expressions. &lt;br /&gt;
&lt;br /&gt;
The other nodes are as described in the CDK.&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking ==&lt;br /&gt;
&lt;br /&gt;
The type checking visitor class could process the whole AST in one go, tagging all types and possible errors. Then, in a following step, the code generator would use this information without further use of a type checker. While this favors a step-by-step processing of the AST, it mandates the full implementation of the type checking visitor (i.e., all methods would have to be non-empty). The approach shown in this example, however, can be use partially implemented visitors, since it only needs to provide implementations for the nodes that have types to be checked. In this approach, the code generator creates a type checker &#039;&#039;whenever&#039;&#039; it needs to perform a check. &lt;br /&gt;
&lt;br /&gt;
=== The ASSERT_UNSPEC macro ===&lt;br /&gt;
The type checker avoids visiting the same nodes by testing (initial assertion) whether it has done so before.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
  #define ASSERT_UNSPEC  { \&lt;br /&gt;
    if (node-&amp;gt;type() != nullptr &amp;amp;&amp;amp; !node-&amp;gt;is_typed(cdk::TYPE_UNSPEC)) \&lt;br /&gt;
      return; \&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the use of this macro is restricted to visits to nodes that have a type, i.e., expressions.&lt;br /&gt;
&lt;br /&gt;
=== The CHECK_TYPES and ASSERT_SAFE_EXPRESSIONS macros ===&lt;br /&gt;
&lt;br /&gt;
The code generator may use the following macros at the start of a visit method, to ensure that the expressions present in a node are safe to use, i.e., that they are semantically consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define CHECK_TYPES(compiler, symtab, node) { \&lt;br /&gt;
  try { \&lt;br /&gt;
    tiny::type_checker checker(compiler, symtab, this); \&lt;br /&gt;
    (node)-&amp;gt;accept(&amp;amp;checker, 0); \&lt;br /&gt;
  } \&lt;br /&gt;
  catch (const std::string &amp;amp;problem) { \&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; (node)-&amp;gt;lineno() &amp;lt;&amp;lt; &amp;quot;: &amp;quot; &amp;lt;&amp;lt; problem &amp;lt;&amp;lt; std::endl; \&lt;br /&gt;
    return; \&lt;br /&gt;
  } \&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define ASSERT_SAFE_EXPRESSIONS CHECK_TYPES(_compiler, _symtab, node)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The type checking visitor ===&lt;br /&gt;
{{CollapsedCode|File type_checker.cpp|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::type_checker::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  auto symbol =  tiny::make_symbol(node-&amp;gt;type(), id, 0);&lt;br /&gt;
  if (!_symtab.insert(id, symbol))&lt;br /&gt;
    throw id + &amp;quot; redeclared&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (node-&amp;gt;initializer()) {&lt;br /&gt;
    node-&amp;gt;initializer()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    if (node-&amp;gt;type() != node-&amp;gt;initializer()-&amp;gt;type())&lt;br /&gt;
      throw std::string(&amp;quot;wrong type for initializer&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _parent-&amp;gt;set_new_symbol(symbol);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_STRING));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  const std::string &amp;amp;id = node-&amp;gt;name();&lt;br /&gt;
  auto symbol = _symtab.find(id);&lt;br /&gt;
  if (!symbol) throw id + &amp;quot; undeclared&amp;quot;;&lt;br /&gt;
  node-&amp;gt;type(symbol-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl+4);&lt;br /&gt;
  if (node-&amp;gt;lvalue()-&amp;gt;type() != node-&amp;gt;rvalue()-&amp;gt;type())&lt;br /&gt;
    throw std::string(&amp;quot;wrong types in assignment&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(node-&amp;gt;lvalue()-&amp;gt;type());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;left()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (left)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!node-&amp;gt;right()-&amp;gt;is_typed(cdk::TYPE_INT))&lt;br /&gt;
    throw std::string(&amp;quot;integer expression expected in add operator (right)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void tiny::type_checker::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_UNSPEC;&lt;br /&gt;
  node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  if (!(node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT) || node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_STRING)))&lt;br /&gt;
    throw std::string(&amp;quot;wrong type in write expression&amp;quot;);&lt;br /&gt;
  node-&amp;gt;type(cdk::primitive_type::create(4, cdk::TYPE_INT));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Code Generation ==&lt;br /&gt;
&lt;br /&gt;
The following code presents just the bare minimum for defining the code generation visitors (the omitted parts are as in Simple).&lt;br /&gt;
&lt;br /&gt;
=== The C code generator ===&lt;br /&gt;
{{CollapsedCode|File c_writer.cpp|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void tiny::c_writer::do_program_node(program_node *const node, int lvl) {&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;int main() {\n&amp;quot;;&lt;br /&gt;
  node-&amp;gt;declarations()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  node-&amp;gt;expressions()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot;  return 0;\n}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_sequence_node(cdk::sequence_node *const node, int lvl) {&lt;br /&gt;
  for (size_t i = 0; i &amp;lt; node-&amp;gt;size(); i++) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    node-&amp;gt;node(i)-&amp;gt;accept(this, lvl);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;;\n&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_declaration_node(declaration_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  std::string &amp;amp;id = node-&amp;gt;identifier();&lt;br /&gt;
  if (new_symbol() != nullptr) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; std::string(lvl+2, &#039; &#039;);&lt;br /&gt;
    if (node-&amp;gt;is_typed(cdk::TYPE_INT)) os() &amp;lt;&amp;lt; &amp;quot;int &amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    else os() &amp;lt;&amp;lt; &amp;quot;char *&amp;quot; &amp;lt;&amp;lt; id;&lt;br /&gt;
    if (node-&amp;gt;initializer()) os() &amp;lt;&amp;lt; &amp;quot; = \&amp;quot;&amp;quot; &amp;lt;&amp;lt; *node-&amp;gt;initializer() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    reset_new_symbol();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_integer_node(cdk::integer_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_string_node(cdk::string_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;value();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_variable_node(cdk::variable_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  os() &amp;lt;&amp;lt; node-&amp;gt;name();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_assignment_node(cdk::assignment_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;lvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; = &amp;quot;;&lt;br /&gt;
  node-&amp;gt;rvalue()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_add_node(cdk::add_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  node-&amp;gt;left()-&amp;gt;accept(this, lvl);&lt;br /&gt;
  os() &amp;lt;&amp;lt; &amp;quot; + &amp;quot;;&lt;br /&gt;
  node-&amp;gt;right()-&amp;gt;accept(this, lvl);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
void tiny::c_writer::do_write_node(write_node *const node, int lvl) {&lt;br /&gt;
  ASSERT_SAFE_EXPRESSIONS;&lt;br /&gt;
  if (node-&amp;gt;argument()-&amp;gt;is_typed(cdk::TYPE_INT)) {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%d\\n\&amp;quot;, &amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;printf(\&amp;quot;%s\\n\&amp;quot;, \&amp;quot;&amp;quot;;&lt;br /&gt;
    node-&amp;gt;argument()-&amp;gt;accept(this, lvl+2);&lt;br /&gt;
    os() &amp;lt;&amp;lt; &amp;quot;\&amp;quot;)&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17766</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17766"/>
		<updated>2026-05-14T17:32:28Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::tensor_type */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::balanced3_type ===&lt;br /&gt;
{{CollapsedCode|File balanced3_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/treg_value.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/treg_alu.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Balanced ternary integer type (40-trit, stored as treg_t).&lt;br /&gt;
   *&lt;br /&gt;
   * Usage in the scanner / parser:&lt;br /&gt;
   *   balanced3_type::value_type *v = new balanced3_type::value_type(42);&lt;br /&gt;
   *   // ... in parser: new balanced3_node(LINE, *$1); delete $1;&lt;br /&gt;
   */&lt;br /&gt;
  struct balanced3_type : public basic_type {&lt;br /&gt;
&lt;br /&gt;
    struct value_type : public treg_value {&lt;br /&gt;
&lt;br /&gt;
      /** Zero (all trits zero = bias in each half). */&lt;br /&gt;
      value_type() { treg_alu::clear(*this); }&lt;br /&gt;
&lt;br /&gt;
      /** From raw halves. */&lt;br /&gt;
      value_type(uint64_t h0, uint64_t h1, uint64_t h2) { set_half(0, h0); set_half(1, h1); set_half(2, h2); }&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
       * From integer — the primary scanner constructor.&lt;br /&gt;
       * Converts a C integer to 40-trit balanced ternary via the ALU.&lt;br /&gt;
       */&lt;br /&gt;
      explicit value_type(int val) : value_type(static_cast&amp;lt;long long&amp;gt;(val)) {}&lt;br /&gt;
      explicit value_type(long long val) {&lt;br /&gt;
        treg_alu::load_int(*this, val);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      /** Back to integer (Horner&#039;s method, 40 trits). */&lt;br /&gt;
      long long to_int64() const {&lt;br /&gt;
        return treg_alu::store_int(*this);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      int to_int() const {&lt;br /&gt;
        long long v = to_int64();&lt;br /&gt;
        if (v &amp;gt; 2147483647LL) return 2147483647;&lt;br /&gt;
        if (v &amp;lt; -2147483648LL) return -2147483648;&lt;br /&gt;
        return static_cast&amp;lt;int&amp;gt;(v);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      /** Decimal string representation of the integer value. */&lt;br /&gt;
      std::string to_string() const {&lt;br /&gt;
        return treg_alu::balanced3_to_string(*this);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      bool operator==(const value_type &amp;amp;o) const {&lt;br /&gt;
        return half(0) == o.half(0) &amp;amp;&amp;amp; half(1) == o.half(1) &amp;amp;&amp;amp; half(2) == o.half(2);&lt;br /&gt;
      }&lt;br /&gt;
      bool operator!=(const value_type &amp;amp;o) const { return !(*this == o); }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    explicit balanced3_type(explicit_call_disabled) :&lt;br /&gt;
        basic_type(8, TYPE_BALANCED3) {  // packed: single uint64_t (40 trits)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~balanced3_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create() {&lt;br /&gt;
      return std::make_shared&amp;lt;balanced3_type&amp;gt;(explicit_call_disabled());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;balanced3_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    std::string to_string() const override { return &amp;quot;balanced3&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::posit3_type ===&lt;br /&gt;
{{CollapsedCode|File posit3_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/treg_value.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/treg_alu.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Logarithmic ternary posit real type (80-trit, stored as treg_t).&lt;br /&gt;
   *&lt;br /&gt;
   * The value_type wraps treg_value, exposing constructors for the&lt;br /&gt;
   * scanner to create values from decimal string literals:&lt;br /&gt;
   *&lt;br /&gt;
   *   auto *v = new posit3_type::value_type(&amp;quot;3.14&amp;quot;);&lt;br /&gt;
   *   // in parser: new posit3_node(LINE, *$1); delete $1;&lt;br /&gt;
   */&lt;br /&gt;
  struct posit3_type : public basic_type {&lt;br /&gt;
&lt;br /&gt;
    struct value_type : public treg_value {&lt;br /&gt;
&lt;br /&gt;
      /** Zero. */&lt;br /&gt;
      value_type() { treg_alu::clear(*this); }&lt;br /&gt;
&lt;br /&gt;
      /** From raw halves. */&lt;br /&gt;
      value_type(uint64_t h0, uint64_t h1, uint64_t h2) { set_half(0, h0); set_half(1, h1); set_half(2, h2); }&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
       * From decimal string — the primary scanner constructor.&lt;br /&gt;
       * Parses the string and converts to 80-trit logarithmic posit&lt;br /&gt;
       * entirely via balanced ternary arithmetic (no floating-point).&lt;br /&gt;
       */&lt;br /&gt;
      explicit value_type(const char *s) {&lt;br /&gt;
        treg_alu::load_posit3(*this, s);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      /** From balanced3 integer value. */&lt;br /&gt;
      explicit value_type(const balanced3_type::value_type &amp;amp;b3) {&lt;br /&gt;
        treg_alu::load_posit3_from_balanced3(*this, b3);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      /** Decimal string representation of the real value. */&lt;br /&gt;
      std::string to_string() const {&lt;br /&gt;
        return treg_alu::posit3_to_string(*this);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      bool operator==(const value_type &amp;amp;o) const {&lt;br /&gt;
        return half(0) == o.half(0) &amp;amp;&amp;amp; half(1) == o.half(1) &amp;amp;&amp;amp; half(2) == o.half(2);&lt;br /&gt;
      }&lt;br /&gt;
      bool operator!=(const value_type &amp;amp;o) const { return !(*this == o); }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    explicit posit3_type(explicit_call_disabled) :&lt;br /&gt;
        basic_type(16, TYPE_POSIT3) {&lt;br /&gt;
      // packed: two uint64_t halves (80 trits)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~posit3_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create() {&lt;br /&gt;
      return std::make_shared&amp;lt;posit3_type&amp;gt;(explicit_call_disabled());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;posit3_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    std::string to_string() const override { return &amp;quot;posit3&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::takum3_type ===&lt;br /&gt;
{{CollapsedCode|File takum3_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/treg_value.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/treg_alu.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Logarithmic ternary takum real type (80-trit, stored as treg_t).&lt;br /&gt;
   *&lt;br /&gt;
   * Hunhold Definition 2 (2024) adapted for balanced ternary with base 3.&lt;br /&gt;
   * Fixed 2-trit regime field; variable characteristic and mantissa.&lt;br /&gt;
   */&lt;br /&gt;
  struct takum3_type : public basic_type {&lt;br /&gt;
&lt;br /&gt;
    struct value_type : public treg_value {&lt;br /&gt;
&lt;br /&gt;
      /** Zero. */&lt;br /&gt;
      value_type() { treg_alu::clear(*this); }&lt;br /&gt;
&lt;br /&gt;
      /** From raw halves. */&lt;br /&gt;
      value_type(uint64_t h0, uint64_t h1, uint64_t h2) { set_half(0, h0); set_half(1, h1); set_half(2, h2); }&lt;br /&gt;
&lt;br /&gt;
      /**&lt;br /&gt;
       * From decimal string — the primary scanner constructor.&lt;br /&gt;
       * Parses the string and converts to 80-trit logarithmic takum&lt;br /&gt;
       * entirely via balanced ternary arithmetic (no floating-point).&lt;br /&gt;
       */&lt;br /&gt;
      explicit value_type(const char *s) {&lt;br /&gt;
        treg_alu::load_takum3(*this, s);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      /** From balanced3 integer value. */&lt;br /&gt;
      explicit value_type(const balanced3_type::value_type &amp;amp;b3) {&lt;br /&gt;
        treg_alu::load_takum3_from_balanced3(*this, b3);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      /** Decimal string representation of the real value. */&lt;br /&gt;
      std::string to_string() const {&lt;br /&gt;
        return treg_alu::takum3_to_string(*this);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      bool operator==(const value_type &amp;amp;o) const {&lt;br /&gt;
        return half(0) == o.half(0) &amp;amp;&amp;amp; half(1) == o.half(1) &amp;amp;&amp;amp; half(2) == o.half(2);&lt;br /&gt;
      }&lt;br /&gt;
      bool operator!=(const value_type &amp;amp;o) const { return !(*this == o); }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    explicit takum3_type(explicit_call_disabled) :&lt;br /&gt;
        basic_type(16, TYPE_TAKUM3) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~takum3_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create() {&lt;br /&gt;
      return std::make_shared&amp;lt;takum3_type&amp;gt;(explicit_call_disabled());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;takum3_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    std::string to_string() const override { return &amp;quot;takum3&amp;quot;; }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/balanced3_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/posit3_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/takum3_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17765</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17765"/>
		<updated>2026-05-14T17:29:07Z</updated>

		<summary type="html">&lt;p&gt;Root: /* The Symbol Table */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/balanced3_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/posit3_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/takum3_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17764</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17764"/>
		<updated>2026-05-14T17:28:27Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Convenience functions for handling types */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/balanced3_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/posit3_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/takum3_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17763</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17763"/>
		<updated>2026-05-14T17:27:21Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Representing and Manipulating Types */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17762</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17762"/>
		<updated>2026-05-14T17:26:11Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::lvalue_node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17761</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17761"/>
		<updated>2026-05-14T17:25:23Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::expression_node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_LVALUE_NODE_H__&lt;br /&gt;
#define __CDK15_LVALUE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17760</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17760"/>
		<updated>2026-05-14T17:24:52Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::typed_node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_LVALUE_NODE_H__&lt;br /&gt;
#define __CDK15_LVALUE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17759</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17759"/>
		<updated>2026-05-14T17:24:03Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::primitive_type */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_LVALUE_NODE_H__&lt;br /&gt;
#define __CDK15_LVALUE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17758</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17758"/>
		<updated>2026-05-14T17:23:43Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::basic_type */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_LVALUE_NODE_H__&lt;br /&gt;
#define __CDK15_LVALUE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17757</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17757"/>
		<updated>2026-05-14T17:23:22Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Symbol representation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_LVALUE_NODE_H__&lt;br /&gt;
#define __CDK15_LVALUE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17756</id>
		<title>Semantic Analysis</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Semantic_Analysis&amp;diff=17756"/>
		<updated>2026-05-14T17:22:56Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Class cdk::functional_type */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{NAVCompiladores}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&lt;br /&gt;
Semantic analysis is mostly concerned with types associated with language objects and how these types are used by the language constructs that depend on them, such as functions and arithmetic operators.&lt;br /&gt;
&lt;br /&gt;
Types can be implicitly specified (e.g., in literals) and inferred (e.g., from operations). This is the case of languages such as Python and other scripting languages, able to make type inference at run time. It can also in languages such as C++ (&#039;&#039;&#039;auto&#039;&#039;&#039;) and Java (&#039;&#039;&#039;var&#039;&#039;&#039;), that make type inference at compile time.&lt;br /&gt;
&lt;br /&gt;
On the other hand, typed entities may be explicitly declared. This is how most statically compiled languages work: the program&#039;s entities are explicitly typed and types may be verified by the compiler.&lt;br /&gt;
&lt;br /&gt;
This section focuses on type checking, based on the abstract syntax tree&#039;s nodes, specifically those that declare typed entities (declarations of typed program entities, such as functions and variables), and those that use those entities (functions and operators). The entities themselves, of course, must remember their own types, so that they may require compliance.&lt;br /&gt;
&lt;br /&gt;
== Representing Typed Information in the AST ==&lt;br /&gt;
&lt;br /&gt;
Type information is present in the AST itself. This information may be directly set by the parser, during syntactic analysis, e.g. in declarations, or it may be set -- the most usual way -- during semantic analysis.&lt;br /&gt;
&lt;br /&gt;
The main nodes involved in representing types are the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;typed_node&#039;&#039;&#039; -- this is the superclass of any node that bears a type. It also provides a convenient interface for checking and managing types.&lt;br /&gt;
* &#039;&#039;&#039;expression_node&#039;&#039;&#039; -- this is a subclass of &#039;&#039;&#039;typed_node&#039;&#039;&#039; that represents program expressions, that is, any value that can be used by a program. Expressions may be primitive, e.g. literals, or composed by other expressions, e.g. operators.&lt;br /&gt;
* &#039;&#039;&#039;lvalue_node&#039;&#039;&#039; -- left-values denote the write-compatible memory locations, these are not the usual values denoted by expression nodes, although any left-value can be converted into an expression, either by considering the memory address it represents (a pointer), or the value at that location (&#039;&#039;&#039;rvalue_node&#039;&#039;&#039;). Left-values are usually known as variables:&#039;&#039;&#039;variable_node&#039;&#039;&#039;, in the simplest case; &#039;&#039;&#039;index_node&#039;&#039;&#039; (for instance) in a more elaborate one.&lt;br /&gt;
* Other cases of typed nodes correspond, in certain languages, to function and variable declarations.&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::typed_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File typed_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_TYPEDNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/basic_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Typed nodes store a type description.&lt;br /&gt;
   */&lt;br /&gt;
  class typed_node: public basic_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    // This must be a pointer, so that we can anchor a dynamic&lt;br /&gt;
    // object and be able to change/delete it afterwards.&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _type;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line number corresponding to&lt;br /&gt;
     * the node&lt;br /&gt;
     */&lt;br /&gt;
    typed_node(int lineno) :&lt;br /&gt;
        basic_node(lineno), _type(nullptr) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; type() {&lt;br /&gt;
      return _type;&lt;br /&gt;
    }&lt;br /&gt;
    void type(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      _type = type;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    bool is_typed(typename_type name) const {&lt;br /&gt;
      return _type-&amp;gt;name() == name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::expression_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File expression_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
#define __CDK15_AST_EXPRESSIONNODE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Expressions are typed nodes that have a value.&lt;br /&gt;
   */&lt;br /&gt;
  class expression_node: public typed_node {&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    /**&lt;br /&gt;
     * @param lineno the source code line corresponding to the node&lt;br /&gt;
     */&lt;br /&gt;
    expression_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::lvalue_node ===&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File lvalue_node.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __CDK15_LVALUE_NODE_H__&lt;br /&gt;
#define __CDK15_LVALUE_NODE_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/ast/typed_node.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /**&lt;br /&gt;
   * Class for describing syntactic tree leaves for lvalues.&lt;br /&gt;
   */&lt;br /&gt;
  class lvalue_node: public typed_node {&lt;br /&gt;
  protected:&lt;br /&gt;
    lvalue_node(int lineno) :&lt;br /&gt;
        typed_node(lineno) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Declarations and definitions ===&lt;br /&gt;
Declarations and definitions can be seen as typed nodes since they declare entities that bear types. The precise definition of these nodes depends on the language and, thus, the nodes are not provided by the CDK. In general, though, they all have to be able to store one or more names (the entity or entities) being declared/defined (variables, functions, and so on) and, possibly, other information (e.g., access qualifiers).&lt;br /&gt;
&lt;br /&gt;
== Representing and Manipulating Types ==&lt;br /&gt;
&lt;br /&gt;
Types are used to characterize the memory used by the various language entities (described by one or more AST nodes).&lt;br /&gt;
&lt;br /&gt;
Types should not be confused with AST nodes.&lt;br /&gt;
&lt;br /&gt;
The CDK has four base definitions. They are, in general, sufficient for most languages, and are easily extended.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;basic_type&#039;&#039;&#039; -- this is the abstract superclass. It is used mostly to refer to unknown or general types.&lt;br /&gt;
* &#039;&#039;&#039;primitive_type&#039;&#039;&#039; -- this class is used to represent any &amp;quot;atomic&amp;quot; data type (that is, unstructured or non-reference types).&lt;br /&gt;
* &#039;&#039;&#039;reference_type&#039;&#039;&#039; -- this class is used to describe reference/pointer types.&lt;br /&gt;
* &#039;&#039;&#039;structured_type&#039;&#039;&#039; -- this class allows for the definition of complex (i.e., hierarchical) data types: it is suitable for describing tuples or structures/classes.&lt;br /&gt;
* &#039;&#039;&#039;functional_type&#039;&#039;&#039; -- this class allows for the definition of types for function objects: it is suitable for describing input/output types for functions.&lt;br /&gt;
* &#039;&#039;&#039;tensor_type&#039;&#039;&#039; -- this class allows for the definition of types for tensor objects (multidimensional arrays).&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::basic_type ===&lt;br /&gt;
In addition to providing a base representation for all type references, it also provides two operators for comparing any two types.&lt;br /&gt;
{{CollapsedCode|File basic_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a general type concept. */&lt;br /&gt;
  class basic_type {&lt;br /&gt;
    size_t _size = 0; // in bytes&lt;br /&gt;
    typename_type _name = TYPE_UNSPEC;&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
    struct explicit_call_disabled {};&lt;br /&gt;
&lt;br /&gt;
  protected:&lt;br /&gt;
&lt;br /&gt;
    basic_type() : _size(0), _name(TYPE_UNSPEC) { }&lt;br /&gt;
    basic_type(size_t size, typename_type name) : _size(size), _name(name) { }&lt;br /&gt;
&lt;br /&gt;
    virtual ~basic_type() noexcept = 0;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t size() const { return _size; }&lt;br /&gt;
    typename_type name() const { return _name; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    virtual std::string to_string() const = 0;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  inline bool operator==(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return t1-&amp;gt;size() == t2-&amp;gt;size() &amp;amp;&amp;amp; t1-&amp;gt;name() == t2-&amp;gt;name();&lt;br /&gt;
  }&lt;br /&gt;
  inline bool operator!=(const std::shared_ptr&amp;lt;basic_type&amp;gt; t1, const std::shared_ptr&amp;lt;basic_type&amp;gt; t2) {&lt;br /&gt;
    return !(t1 == t2);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::primitive_type ===&lt;br /&gt;
{{CollapsedCode|File primitive_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/typename_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** Primitive (i.e., non-structured non-indirect) types. */&lt;br /&gt;
  class primitive_type: public basic_type {&lt;br /&gt;
  public:&lt;br /&gt;
    explicit primitive_type(explicit_call_disabled, size_t size, typename_type name) :&lt;br /&gt;
        basic_type(size, name) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~primitive_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(size_t size, typename_type name) {&lt;br /&gt;
      return std::make_shared&amp;lt;primitive_type&amp;gt;(explicit_call_disabled(), size, name);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;primitive_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      if (name() == TYPE_INT) return &amp;quot;integer&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_DOUBLE) return &amp;quot;double&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_STRING) return &amp;quot;string&amp;quot;;&lt;br /&gt;
      if (name() == TYPE_VOID) return &amp;quot;void&amp;quot;;&lt;br /&gt;
      return &amp;quot;UNKNOWN-TYPE:&amp;quot; + std::to_string(name());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::reference_type ===&lt;br /&gt;
{{CollapsedCode|File reference_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a reference type concept (such as a C pointer or a C++ reference). */&lt;br /&gt;
  struct reference_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; _referenced = nullptr;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit reference_type(explicit_call_disabled, size_t size,  std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) :&lt;br /&gt;
        basic_type(size, TYPE_POINTER), _referenced(referenced) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~reference_type() = default;&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; referenced() const { return _referenced; }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return &amp;quot;@&amp;quot; + _referenced-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(size_t size, std::shared_ptr&amp;lt;basic_type&amp;gt; referenced) {&lt;br /&gt;
      return std::make_shared&amp;lt;reference_type&amp;gt;(explicit_call_disabled(), size, referenced);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;reference_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::structured_type ===&lt;br /&gt;
{{CollapsedCode|File structured_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a structured type concept. */&lt;br /&gt;
  class structured_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; _components;&lt;br /&gt;
&lt;br /&gt;
  private:&lt;br /&gt;
    size_t compute_size(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      for (auto component : components)&lt;br /&gt;
        size += component-&amp;gt;size();&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    explicit structured_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;components) :&lt;br /&gt;
        basic_type(compute_size(components), TYPE_STRUCT), _components(components) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~structured_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; component(size_t ix) { return _components[ix]; }&lt;br /&gt;
    const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt;&amp;amp; components() const { return _components; }&lt;br /&gt;
    size_t length() const { return _components.size(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string result = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
      return std::accumulate(_components.begin(), _components.end(), result,&lt;br /&gt;
                             [] (auto a, auto b) { return a + &amp;quot;,&amp;quot; + b-&amp;gt;to_string(); });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;types) {&lt;br /&gt;
      return std::make_shared&amp;lt;structured_type&amp;gt;(explicit_call_disabled(), types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;structured_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::functional_type ===&lt;br /&gt;
{{CollapsedCode|File functional_type.h|&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  /** This class represents a functional type concept. */&lt;br /&gt;
  class functional_type: public basic_type {&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _input;&lt;br /&gt;
    std::shared_ptr&amp;lt;structured_type&amp;gt; _output;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit functional_type(explicit_call_disabled, const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input,&lt;br /&gt;
                             const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output) :&lt;br /&gt;
        basic_type(4, TYPE_FUNCTIONAL), _input(structured_type::create(input)), _output(structured_type::create(output)) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~functional_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; input(size_t ix) { return _input-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;input() const { return _input; }&lt;br /&gt;
    size_t input_length() const { return _input-&amp;gt;length(); }&lt;br /&gt;
    std::shared_ptr&amp;lt;basic_type&amp;gt; output(size_t ix) { return _output-&amp;gt;component(ix); }&lt;br /&gt;
    const std::shared_ptr&amp;lt;structured_type&amp;gt; &amp;amp;output() const { return _output; }&lt;br /&gt;
    size_t output_length() const { return _output-&amp;gt;length(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const { return _input-&amp;gt;to_string() + &amp;quot;:&amp;quot; + _output-&amp;gt;to_string(); }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;input_types, &lt;br /&gt;
                       const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; &amp;amp;output_types) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; input_types;&lt;br /&gt;
      return std::make_shared&amp;lt;functional_type&amp;gt;(explicit_call_disabled(), input_types, output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::shared_ptr&amp;lt;basic_type&amp;gt; &amp;amp;output_type) {&lt;br /&gt;
      std::vector&amp;lt;std::shared_ptr&amp;lt;basic_type&amp;gt;&amp;gt; output_types = { output_type };&lt;br /&gt;
      return create(output_types);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;functional_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Class cdk::tensor_type ===&lt;br /&gt;
{{CollapsedCode|File tensor_type.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;numeric&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  class tensor_type: public basic_type {&lt;br /&gt;
    std::vector&amp;lt;size_t&amp;gt; _dims;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    // size 4 is because this is actually just a pointer&lt;br /&gt;
    explicit tensor_type(explicit_call_disabled, const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) :&lt;br /&gt;
        basic_type(4, TYPE_TENSOR), _dims(dims) {&lt;br /&gt;
      // EMPTY&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    ~tensor_type() = default;&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    size_t dim(size_t ix) const { return _dims.at(ix); }&lt;br /&gt;
    const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims() const { return _dims; }&lt;br /&gt;
    size_t n_dims() const { return _dims.size(); }&lt;br /&gt;
&lt;br /&gt;
    size_t size() const {&lt;br /&gt;
      size_t size = 0;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) size = _dims.at(0);&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        size *= _dims.at(ix);&lt;br /&gt;
      return size;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    std::string to_string() const {&lt;br /&gt;
      std::string s = &amp;quot;[&amp;quot;;&lt;br /&gt;
      if (_dims.size() &amp;gt;= 1) s += std::to_string(_dims.at(0));&lt;br /&gt;
      for (size_t ix = 1; ix &amp;lt; _dims.size(); ix++)&lt;br /&gt;
        s += &#039;,&#039; + std::to_string(_dims.at(ix));&lt;br /&gt;
      return s + &amp;quot;]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
&lt;br /&gt;
    static auto create(const std::vector&amp;lt;size_t&amp;gt; &amp;amp;dims) {&lt;br /&gt;
      return std::make_shared&amp;lt;tensor_type&amp;gt;(explicit_call_disabled(), dims);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static auto cast(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
      return std::dynamic_pointer_cast&amp;lt;tensor_type&amp;gt;(type);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Convenience functions for handling types ===&lt;br /&gt;
The following functions are provided for convenience: they allow for writing clearer code. &lt;br /&gt;
&lt;br /&gt;
Implementations have been omitted for the sake of clarity (they are available in the CDK).&lt;br /&gt;
{{CollapsedCode|File types.h|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#pragma once&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/primitive_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/reference_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/structured_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/functional_type.h&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/tensor_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  inline std::string to_string(std::shared_ptr&amp;lt;basic_type&amp;gt; type) {&lt;br /&gt;
    return type-&amp;gt;to_string();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // cdk&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== The Symbol Table ==&lt;br /&gt;
&lt;br /&gt;
A interface pública da tabela de símbolos é a seguinte (foram omitidas todas as partes não públicas, assim como os métodos de construção/destruição):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;push&#039;&#039;&#039; - create a new context and make it current.&lt;br /&gt;
* &#039;&#039;&#039;pop&#039;&#039;&#039; - destroy the current context: the previous context becomes the current one. If the first context is reached no operation is performed.&lt;br /&gt;
* &#039;&#039;&#039;insert&#039;&#039;&#039; - define a new identifier in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if this is a new identifier (may shadow another defined in an upper context). Returns false if the identifier already exists in the current context.&lt;br /&gt;
* &#039;&#039;&#039;replace_local&#039;&#039;&#039; - replace the data corresponding to a symbol in the current context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; - replace the data corresponding to a symbol (look for the symbol in all available contexts, starting with the innermost one): &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns true if the symbol exists; false if the symbol does not exist in any of the contexts.&lt;br /&gt;
* &#039;&#039;&#039;find_local&#039;&#039;&#039; - search for a symbol in the local (current) context: &#039;&#039;name&#039;&#039; is the symbol&#039;s name; &#039;&#039;symbol&#039;&#039; is the symbol. Returns the symbol if it exists; and nullptr if the symbol does not exist in the current context.&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; - search for a symbol in the avaible contexts, starting with the first one and proceeding until reaching the outermost context. &#039;&#039;name&#039;&#039; is the symbol&#039;s name;  from how many contexts up from the current one (zero). Returns nullptr if the symbol cannot be found in any of the contexts; or, the symbol and corresponding attributes.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol_table.h (interface summary)|&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
namespace cdk {&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;typename Symbol&amp;gt;&lt;br /&gt;
  class symbol_table {&lt;br /&gt;
  public:&lt;br /&gt;
    void push();&lt;br /&gt;
&lt;br /&gt;
    void pop();&lt;br /&gt;
&lt;br /&gt;
    bool insert(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace_local(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    bool replace(const std::string &amp;amp;name, std::shared_ptr&amp;lt;Symbol&amp;gt; symbol);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find_local(const std::string &amp;amp;name);&lt;br /&gt;
&lt;br /&gt;
    std::shared_ptr&amp;lt;Symbol&amp;gt; find(const std::string &amp;amp;name, size_t from = 0) const;&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Symbol representation ==&lt;br /&gt;
&lt;br /&gt;
Symbols describe named program entities and store their properties. They provide support for the semantic processor: declarations create new symbols. Expressions and left-values refer to those symbols.&lt;br /&gt;
&lt;br /&gt;
A simple representation in this case could be done in the following way. Note that this definition is just an example and contains only minimal information. It should be extended to account for the needs of the language being implemented.&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|File symbol.h (Tiny language)|&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
#define __TINY_TARGETS_SYMBOL_H__&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string&amp;gt;&lt;br /&gt;
#include &amp;lt;memory&amp;gt;&lt;br /&gt;
#include &amp;lt;cdk/types/basic_type.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tiny {&lt;br /&gt;
&lt;br /&gt;
  class symbol {&lt;br /&gt;
    std::string _name; // identifier&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; _type; // type (type id + type size)&lt;br /&gt;
  public:&lt;br /&gt;
    // constructors, destructor, getters, etc.&lt;br /&gt;
&lt;br /&gt;
  public:&lt;br /&gt;
    // critical for type checking (interface similar to that of class cdk::typed_node)&lt;br /&gt;
    std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type() const { return _type; }&lt;br /&gt;
    void set_type(std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; t) { _type = t; }&lt;br /&gt;
    bool is_typed(cdk::typename_type name) const { return _type-&amp;gt;name() == name; }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // this function simplifies symbol creation in the type_checker visitor (see below)&lt;br /&gt;
  inline auto make_symbol(const std::string &amp;amp;name, std::shared_ptr&amp;lt;cdk::basic_type&amp;gt; type, /* rest of ctor args */) {&lt;br /&gt;
    return std::make_shared&amp;lt;symbol&amp;gt;(name, type, /* rest of ctor args */);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
} // tiny&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Type Checking: Using Visitors ==&lt;br /&gt;
&lt;br /&gt;
Type checking is the process of verifying whether the types used in the various language constructs are appropriate. It can be performed at compile time (static type checking) or at run time.&lt;br /&gt;
&lt;br /&gt;
The type checking discussed here is the static approach, i.e., checking whether the types used for objects and the operations that manipulate them at compile time are consistent.&lt;br /&gt;
&lt;br /&gt;
In the approach followed by CDK-based compilers, code generation is carried out by visitors that are responsible for traversing the abstract syntax tree and generate, evaluating each node. Node evaluation may depend on the specificities of the data types being manipulated, the simplest of which is the data type&#039;s size, important in all memory-related operations.&lt;br /&gt;
&lt;br /&gt;
== Vídeo Explicativo ==&lt;br /&gt;
O vídeo seguinte explica os tópicos apresentados nesta página (aplicação a várias linguagens).&lt;br /&gt;
&lt;br /&gt;
* Linguagem UDF (2024/2025): https://www.youtube.com/watch?v=x9uJ_Wn6360&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
=== Type checking example: the Tiny language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers a simple grammar and performs the whole of the semantic analysis process and, finally, generates the corresponding C code. The semantic analysis process must account for variables (they must be declared before they can be used) and for their types (all types must be used correctly).&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Tiny language: semantic analysis example and C generation|The Tiny language: semantic analysis example and C generation]]&lt;br /&gt;
&lt;br /&gt;
=== Type checking example: the Simple language ===&lt;br /&gt;
&lt;br /&gt;
The following example considers an evolution of Compact, called Simple. Where Compact forces some verification via syntactic analysis (thus, presenting low flexibility), Simple has a richer grammar and, consequently, admits constructions that may not be correct in what concerns types of operators, functions, and their arguments. Type checking in this case is built-in, since, without it, it would be impossible to guarantee the correctness of any expression.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Simple language: semantic analysis|The Simple language: semantic analysis]]&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=== Type checking example: the Compact language [obsolete]===&lt;br /&gt;
&lt;br /&gt;
The following example presents an old version of the Compact compiler. This case is no longer relevant, but shows how an existing compiler can be extended.&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/The Compact language: semantic analysis example and C generation|The Compact language: semantic analysis example and C generation]]&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
* [[Semantic Analysis/Exercise 01|Exercise 01]] - The &amp;quot;Let&amp;quot; language&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:XYc.jpg&amp;diff=17755</id>
		<title>File:XYc.jpg</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:XYc.jpg&amp;diff=17755"/>
		<updated>2026-05-11T15:27:33Z</updated>

		<summary type="html">&lt;p&gt;Root: Root uploaded a new version of File:XYc.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:RXb2.jpg&amp;diff=17754</id>
		<title>File:RXb2.jpg</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:RXb2.jpg&amp;diff=17754"/>
		<updated>2026-05-11T15:18:59Z</updated>

		<summary type="html">&lt;p&gt;Root: Root uploaded a new version of File:RXb2.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:RXb1.jpg&amp;diff=17753</id>
		<title>File:RXb1.jpg</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:RXb1.jpg&amp;diff=17753"/>
		<updated>2026-05-11T15:10:54Z</updated>

		<summary type="html">&lt;p&gt;Root: Root uploaded a new version of File:RXb1.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:AM2.jpg&amp;diff=17752</id>
		<title>File:AM2.jpg</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:AM2.jpg&amp;diff=17752"/>
		<updated>2026-05-11T14:46:03Z</updated>

		<summary type="html">&lt;p&gt;Root: Root uploaded a new version of File:AM2.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:AM1.jpg&amp;diff=17751</id>
		<title>File:AM1.jpg</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:AM1.jpg&amp;diff=17751"/>
		<updated>2026-05-11T14:45:21Z</updated>

		<summary type="html">&lt;p&gt;Root: Root uploaded a new version of File:AM1.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Bottom-Up_Parsing/Exercise_14:_LALR(1)&amp;diff=17750</id>
		<title>Bottom-Up Parsing/Exercise 14: LALR(1)</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Bottom-Up_Parsing/Exercise_14:_LALR(1)&amp;diff=17750"/>
		<updated>2026-05-11T13:35:17Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Solução */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Problema ==&lt;br /&gt;
&lt;br /&gt;
Consider the following grammar, where A is the initial symbol and &#039;&#039;&#039;{ x, y, z }&#039;&#039;&#039; is the set of terminal symbols: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
A → M z x | z M x | z x z&lt;br /&gt;
M → y | ε&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# Compute the set of LALR(1) states for the grammar. Build the corresponding LALR(1) parse table.&lt;br /&gt;
# Compact the parse table, eliminating and propagating reductions.&lt;br /&gt;
# Show the parsing process for input &#039;&#039;&#039;zyx&#039;&#039;&#039; (including the actions/gotos and the input and stack states). In case of conflict, assume YACC&#039;s behavior.&lt;br /&gt;
&lt;br /&gt;
== Solução ==&lt;br /&gt;
&lt;br /&gt;
Na imagem, os conflitos indicados para a regra 2 são para a regra 5.&lt;br /&gt;
&lt;br /&gt;
Note-se que a solução apresentada é para SLR(1) e LALR(1) (a vermelho).&lt;br /&gt;
&lt;br /&gt;
{{CollapsedCode|Solução completa|&lt;br /&gt;
[[Image:Mzx1.jpg|768px]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Mzx1.jpg&amp;diff=17749</id>
		<title>File:Mzx1.jpg</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Mzx1.jpg&amp;diff=17749"/>
		<updated>2026-05-11T13:32:06Z</updated>

		<summary type="html">&lt;p&gt;Root: Root uploaded a new version of File:Mzx1.jpg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Librts7-202605092235.tar.bz2&amp;diff=17748</id>
		<title>File:Librts7-202605092235.tar.bz2</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Librts7-202605092235.tar.bz2&amp;diff=17748"/>
		<updated>2026-05-09T21:48:22Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Material_de_Apoio_ao_Desenvolvimento&amp;diff=17747</id>
		<title>Compiladores/Projecto de Compiladores/Material de Apoio ao Desenvolvimento</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Material_de_Apoio_ao_Desenvolvimento&amp;diff=17747"/>
		<updated>2026-05-09T21:48:07Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJHEADER}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&amp;lt;!-- &#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A DISPONIBILIZAR BREVEMENTE&amp;lt;/font&amp;gt;&#039;&#039;&#039; --&amp;gt;&lt;br /&gt;
== Material de Apoio == &lt;br /&gt;
&lt;br /&gt;
O projecto, escrito em C++, deve ser desenvolvido considerando os princípios de desenvolvimento de compiladores, assim como os da boa programação com objectos e os aspectos de arquitectura dos padrões de desenho aplicáveis. Notar que esta tarefa está implicitamente facilitada pelo material de apoio, que condiciona o desenvolvimento do compilador.&lt;br /&gt;
&lt;br /&gt;
O código presente nas bibliotecas de apoio (já instalado na máquina virtual) ao desenvolvimento do projecto é de uso obrigatório:&lt;br /&gt;
&lt;br /&gt;
* CDK [[media:libcdk21-202605092235.tar.bz2]] - código de base para o desenvolvimento do compilador&lt;br /&gt;
* RTS [[media:librts7-202605092235.tar.bz2]] - código de base para os programas gerados pelo compilador (runtime)&lt;br /&gt;
&lt;br /&gt;
{{CVSCode|Notar que o [[Compiladores/Projecto de Compiladores/Repositório GIT|repositório GIT]] já contém uma versão do projecto a desenvolver. Isto significa que &#039;&#039;antes&#039;&#039; de se começar a programar, o projecto deve ser obtido a partir do repositório.}}&lt;br /&gt;
&lt;br /&gt;
== Pacotes binários para instalação ==&lt;br /&gt;
&lt;br /&gt;
O manterial de apoio está disponível para instalação directa (não é necessário compilar) através do repositório:&lt;br /&gt;
* https://download.opensuse.org/repositories/home:/d4vid:/co26/openSUSE_Tumbleweed/&lt;br /&gt;
&lt;br /&gt;
Este repositório pode ser adicionado a um openSUSE previamente instalado através do comando:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;zypper ar https://download.opensuse.org/repositories/home:/d4vid:/co26/openSUSE_Tumbleweed/ CO26&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;zypper refresh&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Uma vez adicionado o repositório, os pacotes acima podem ser instalados através dos comandos:&lt;br /&gt;
&lt;br /&gt;
 zypper install libcdk21-devel librts7-devel&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Este material já está instalado na [[Compiladores/Projecto de Compiladores/Máquina Virtual|máquina virtual da disciplina]].}}&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores|P]]&lt;br /&gt;
[[category:Compiladores|P]]&lt;br /&gt;
[[category:Ensino|P]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Libcdk21-202605092235.tar.bz2&amp;diff=17746</id>
		<title>File:Libcdk21-202605092235.tar.bz2</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=File:Libcdk21-202605092235.tar.bz2&amp;diff=17746"/>
		<updated>2026-05-09T21:47:36Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Template:PRJCOMandatory20252026&amp;diff=17745</id>
		<title>Template:PRJCOMandatory20252026</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Template:PRJCOMandatory20252026&amp;diff=17745"/>
		<updated>2026-05-09T21:45:07Z</updated>

		<summary type="html">&lt;p&gt;Root: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{CDKRTS|CDK21|libcdk21-202605092235.tar.bz2|RTS7|librts7-202605092235.tar.bz2}}&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17744</id>
		<title>Compiladores/Projecto de Compiladores/Projecto 2025-2026/Manual de Referência da Linguagem P6</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Projecto_2025-2026/Manual_de_Refer%C3%AAncia_da_Linguagem_P6&amp;diff=17744"/>
		<updated>2026-05-07T15:44:02Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Declaração */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20252026}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
&amp;lt;!--&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;RASCUNHO&#039;&#039;&#039;&amp;lt;/font&amp;gt;--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&#039;&#039;&#039;ÉPOCA NORMAL&#039;&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;P6&#039;&#039;&#039; é 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]].&lt;br /&gt;
&lt;br /&gt;
= Tipos de Dados =&lt;br /&gt;
&lt;br /&gt;
A linguagem é fracamente tipificada (são efectuadas algumas conversões implícitas). Existem 4 tipos de dados básicos, apenas alguns dos quais são compatíveis com a [https://en.wikipedia.org/wiki/C_(programming_language) linguagem C]. O alinhamento em memória binária é sempre a 32 bits. Note-se que alguns dos tipos de dados são ternários e devem ser manipulados com as funções das ALUs disponibilizadas.&lt;br /&gt;
&lt;br /&gt;
* Tipos numéricos: os inteiros são [https://en.wikipedia.org/wiki/Balanced_ternary ternários equilibrados], ocupam 40 trits (empacotados em 64 bits); os reais são ternários e estão representados no formato [https://arxiv.org/abs/2404.18603 Takum] (note-se que a definição neste artigo é para uma representação binária e não é exactamente a que é implementada pelas ALUs ternárias em uso no projecto), ocupam 80 trits (empacotados em 128 bits).&lt;br /&gt;
* As cadeias de caracteres são vectores de caracteres binários terminados por [https://en.wikipedia.org/wiki/ASCII ASCII] NUL (carácter com o valor zero). Variáveis e literais deste tipo só podem ser utilizados em atribuições, impressões, ou como argumentos/retornos de funções. Os caracteres são valores de 8 bits não directamente manipuláveis.&lt;br /&gt;
* Os ponteiros representam endereços de objectos (de qualquer tipo) e ocupam 32 bits. Podem ser objecto de operações aritméticas (deslocamentos) e permitem aceder ao valor apontado. Note-se que não é possível usar inteiros ternários directamente em aritmética de ponteiros (têm de ser convertidos para isso).&lt;br /&gt;
&lt;br /&gt;
Os tipos suportados por cada operador e a operação a realizar são indicados na [[#Expressões|definição das expressões]].&lt;br /&gt;
&lt;br /&gt;
Existem ainda tipos associado a valores funcionais, i.e., tipos que descrevem a interface de funções (ver abaixo). Os valores em memória associados a estes tipos são efectivamente ponteiros, mas para funções e não para dados, podendo ser usados para invocar as funções correspondentes. Estes identificadores não podem ser usados como variáveis (e.g., passados como argumentos de outras funções, etc.).&amp;lt;!--Estes ponteiros não aceitam operações de aritmética de ponteiros ou de indexação (embora ponteiros para estes ponteiros as aceitem).--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Manipulação de Nomes =&lt;br /&gt;
&lt;br /&gt;
Os nomes (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 dos casos. Existem ainda nomes para funções externas à linguagem P6. Tanto em P6, como em C, os nomes das funções referem directamente a posição do código dessas funções (à la C; ver &#039;&#039;&#039;extern&#039;&#039;&#039; abaixo).&lt;br /&gt;
&lt;br /&gt;
== Espaço de nomes e visibilidade dos identificadores ==&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
Os identificadores são visíveis desde a declaração até ao fim do alcance: ficheiro (globais) ou bloco (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 um bloco. É possível utilizar símbolos globais nos contextos dos blocos das funções, mas não é possível declará-los (ver [[#Símbolos globais|símbolos globais]]).&lt;br /&gt;
&lt;br /&gt;
== Validade das variáveis ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
= Convenções Lexicais =&lt;br /&gt;
&lt;br /&gt;
Para cada grupo de elementos lexicais (tokens), considera-se a maior sequência de caracteres constituindo um elemento válido. Assim, por exemplo, a designação &#039;&#039;&#039;&amp;gt;=&#039;&#039;&#039; é sempre um único elemento lexical (por oposição à situação ilegal de se terem dois símbolos: &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; seguido de &#039;&#039;&#039;=&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Caracteres brancos ==&lt;br /&gt;
&lt;br /&gt;
São considerados separadores e não representam nenhum elemento lexical: &#039;&#039;&#039;mudança de linha&#039;&#039;&#039; ASCII LF (&#039;&#039;&#039;0x0A&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039;), &#039;&#039;&#039;recuo do carreto&#039;&#039;&#039; ASCII CR (&#039;&#039;&#039;0x0D&#039;&#039;&#039;, &#039;&#039;&#039;\r&#039;&#039;&#039;), &#039;&#039;&#039;espaço&#039;&#039;&#039; ASCII SP (&#039;&#039;&#039;0x20&#039;&#039;&#039;, ⌴) e &#039;&#039;&#039;tabulação horizontal&#039;&#039;&#039; ASCII HT (&#039;&#039;&#039;0x09&#039;&#039;&#039;, &#039;&#039;&#039;\t&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
== Comentários ==&lt;br /&gt;
&lt;br /&gt;
Existem dois tipos de comentários, que também funcionam como elementos separadores:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;explicativos&#039;&#039;&#039; -- começam com &#039;&#039;&#039;//&#039;&#039;&#039; e acabam no fim da linha; e&lt;br /&gt;
* &#039;&#039;&#039;operacionais&#039;&#039;&#039; -- começam com &#039;&#039;&#039;/*&#039;&#039;&#039; e terminam com &#039;&#039;&#039;*/&#039;&#039;&#039;, podendo estar aninhados.&lt;br /&gt;
&lt;br /&gt;
Se as sequências de início fizerem parte de uma cadeia de caracteres, não iniciam um comentário (ver [[#Cadeias de caracteres|definição das cadeias de caracteres]]).&lt;br /&gt;
&lt;br /&gt;
== Palavras-chave ==&lt;br /&gt;
&lt;br /&gt;
As seguintes palavras-chave são reservadas, não constituindo identificadores (devem ser escritas exactamente como indicado):&lt;br /&gt;
&lt;br /&gt;
* tipos: &#039;&#039;&#039;int real string void&#039;&#039;&#039;&lt;br /&gt;
* declarações: &#039;&#039;&#039;extern forward public auto&#039;&#039;&#039;&lt;br /&gt;
* instruções: &#039;&#039;&#039;if elif else while stop next return&#039;&#039;&#039;&lt;br /&gt;
* expressões: &#039;&#039;&#039;input null sizeof&#039;&#039;&#039;&lt;br /&gt;
* outras: &#039;&#039;&#039;begin end&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Tipos ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais designam tipos em declarações (ver gramática): &#039;&#039;&#039;int&#039;&#039;&#039; (inteiro), &#039;&#039;&#039;real&#039;&#039;&#039; (real), &#039;&#039;&#039;string&#039;&#039;&#039; (cadeia de caracteres). &lt;br /&gt;
&lt;br /&gt;
Os tipos correspondentes a ponteiros são outros tipos delimitados por &#039;&#039;&#039;[&#039;&#039;&#039; e &#039;&#039;&#039;]&#039;&#039;&#039;, designando uma indirecção e não o objecto directo (ver gramática).&lt;br /&gt;
&lt;br /&gt;
Note-se que, quando se tem uma declaração &#039;&#039;&#039;extern&#039;&#039;&#039;, os tipos correspondem aos compatíveis com a linguagem C na mesma arquitectura ix86 de 32 bits, i.e., &#039;&#039;&#039;int&#039;&#039;&#039; corresponde a  um número binário inteiro em [https://en.wikipedia.org/wiki/Two%27s_complement complemento para 2] (32 bits), &#039;&#039;&#039;real&#039;&#039;&#039; coresponde a uma representação segundo a norma [https://en.wikipedia.org/wiki/IEEE_754 IEEE 754] de dupla precisão (64 bits), devendo ser convertidos de e para os tipos nativos da linguage P6 sempre que necessário (ver RTS).&lt;br /&gt;
&lt;br /&gt;
== Operadores de expressões ==&lt;br /&gt;
&lt;br /&gt;
São considerados operadores os elementos lexicais apresentados na definição das expressões.&lt;br /&gt;
&lt;br /&gt;
== Delimitadores e terminadores ==&lt;br /&gt;
&lt;br /&gt;
Os seguintes elementos lexicais são delimitadores/terminadores: &lt;br /&gt;
* &#039;&#039;&#039;,&#039;&#039;&#039; (vírgula)&lt;br /&gt;
* &#039;&#039;&#039;;&#039;&#039;&#039; (ponto e vírgula)&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; (operações de impressão)&lt;br /&gt;
* &#039;&#039;&#039;(&#039;&#039;&#039; e &#039;&#039;&#039;)&#039;&#039;&#039; (delimitadores de expressões)&lt;br /&gt;
* &#039;&#039;&#039;{&#039;&#039;&#039; e &#039;&#039;&#039;}&#039;&#039;&#039; (delimitadores de blocos)&lt;br /&gt;
&lt;br /&gt;
== Identificadores (nomes) ==&lt;br /&gt;
&lt;br /&gt;
São iniciados por uma letra, seguindo-se 0 (zero) ou mais letras ou dígitos. 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.&lt;br /&gt;
&lt;br /&gt;
== Literais ==&lt;br /&gt;
&lt;br /&gt;
São notações para valores constantes de alguns tipos da linguagem (não confundir com constantes, i.e., identificadores que, em algumas linguagens, designam elementos cujo valor não pode ser alterado durante a execução do programa).&lt;br /&gt;
&lt;br /&gt;
=== Inteiros ===&lt;br /&gt;
&lt;br /&gt;
Um literal inteiro é um número não negativo (mas ver a seguir). Números negativos podem ser construídos pela aplicação do operador de negação unária (&#039;&#039;&#039;-&#039;&#039;&#039;) a um literal (sempre positivo).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros decimais são constituídos por sequências de 1 (um) ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;9&#039;&#039;&#039;, em que o primeiro digito não é 0 (zero), excepto no caso do número 0 (zero). Neste caso, é composto apenas pelo dígito 0 (zero) (em qualquer base).&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 9 começam sempre pelo dígito 0 (zero), sendo seguidos de um ou mais dígitos de &#039;&#039;&#039;0&#039;&#039;&#039; a &#039;&#039;&#039;8&#039;&#039;&#039; (note-se que &#039;&#039;&#039;09&#039;&#039;&#039; é um literal inválido em base 9). Exemplo: &#039;&#039;&#039;086 = 78&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Literais inteiros em base 3 (equilibrada) começam sempre com a sequência &#039;&#039;&#039;0t&#039;&#039;&#039;, seguida de um ou mais símbolos dessa base: &#039;&#039;&#039;-&#039;&#039;&#039; (valor &#039;&#039;&#039;-1&#039;&#039;&#039;), &#039;&#039;&#039;0&#039;&#039;&#039; (valor &#039;&#039;&#039;0&#039;&#039;&#039;) e &#039;&#039;&#039;+&#039;&#039;&#039; (valor &#039;&#039;&#039;1&#039;&#039;&#039;). Estes literais podem ser intrinsecamente negativos. Exemplos: &#039;&#039;&#039;0t+0-0 = 24&#039;&#039;&#039;; &#039;&#039;&#039;0t-0+0 = -24&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Se não for possível representar um literal na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
&lt;br /&gt;
=== Reais em formato Takum3 ===&lt;br /&gt;
&lt;br /&gt;
Os literais reais (sempre positivos) são expressos tal como em C (exclusivamente em base 10). &lt;br /&gt;
&lt;br /&gt;
Não existem literais negativos (números negativos resultam da operação unária &#039;&#039;&#039;-&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Note-se que um literal sem &#039;&#039;&#039;.&#039;&#039;&#039; (ponto decimal) nem parte exponencial é do tipo inteiro.&lt;br /&gt;
&lt;br /&gt;
Note-se que, apesar de C normalmente usar uma representação interna em binário no formato IEEE 754, a linguagem P6 usa um formato, representado em ternário, completamente diferente (embora a forma de escrita dos literais seja a mesma).&lt;br /&gt;
&lt;br /&gt;
Exemplos: &#039;&#039;&#039;3.14&#039;&#039;&#039;, &#039;&#039;&#039;1E3&#039;&#039;&#039; = 1000 (número inteiro representado como real). &#039;&#039;&#039;12.34e-24&#039;&#039;&#039; = 12.34 x 10&amp;lt;sup&amp;gt;-24&amp;lt;/sup&amp;gt; (notação cientifica).&lt;br /&gt;
&amp;lt;!--Se não for possível representar um literal real na máquina, devido a overflow, deverá ser gerado um erro lexical.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Cadeias de caracteres ===&lt;br /&gt;
&lt;br /&gt;
As cadeias de caracteres são delimitadas por aspas (&#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;) e podem conter quaisquer caracteres, excepto ASCII NUL (0x00) e ASCII LF (0x0A). Nas cadeias, os delimitadores de comentários não têm significado especial. Se for escrito um literal que contenha &#039;&#039;&#039;\0&#039;&#039;&#039;, então a cadeia termina nessa posição. Exemplo: &#039;&#039;&#039;ab\0xy&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;ab&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
É possível designar caracteres por sequências especiais (iniciadas por &#039;&#039;&#039;\&#039;&#039;&#039;), especialmente úteis quando não existe representação gráfica directa. As sequências especiais correspondem aos caracteres ASCII HT, LF e CR (&#039;&#039;&#039;\t&#039;&#039;&#039;, &#039;&#039;&#039;\n&#039;&#039;&#039; e &#039;&#039;&#039;\r&#039;&#039;&#039;, respectivamente), aspa (&#039;&#039;&#039;\&amp;quot;&#039;&#039;&#039;). &#039;&#039;backslash&#039;&#039; (&#039;&#039;&#039;\\&#039;&#039;&#039;), ou a quaisquer outros especificados através de 1 a 3 dígitos em base 8, designando valores de 8 bits (e.g., &#039;&#039;&#039;\012&#039;&#039;&#039; ou apenas &#039;&#039;&#039;\12&#039;&#039;&#039; se o carácter seguinte não representar um dígito em base 8). Exemplo: &#039;&#039;&#039;xy\012z&#039;&#039;&#039; tem o mesmo significado que &#039;&#039;&#039;xy\12z&#039;&#039;&#039; e que &#039;&#039;&#039;xy\nz&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
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: &#039;&#039;&#039;&amp;quot;ab&amp;quot;&#039;&#039;&#039; &#039;&#039;&#039;&amp;quot;cd&amp;quot;&#039;&#039;&#039; é o mesmo que &#039;&#039;&#039;&amp;quot;abcd&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Ponteiros ===&lt;br /&gt;
&lt;br /&gt;
O único literal admissível para ponteiros corresponde ao ponteiro nulo e é indicado pela palavra-chave &#039;&#039;&#039;null&#039;&#039;&#039;. Este literal é compatível com todos os tipos de ponteiro. Os inteiros não são convertíveis em ponteiros, pelo que o valor &#039;&#039;&#039;0&#039;&#039;&#039; (zero) não é um valor inicial admissível para ponteiros.&lt;br /&gt;
&lt;br /&gt;
Note-se que a aritmética de ponteiros é possível apenas com inteiros binários, mas não com inteiros ternários (estes devem ser convertidos para binário, caso seja necessário).&lt;br /&gt;
&lt;br /&gt;
= Gramática =&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; e &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;. Alguns elementos usados na gramática também são elementos da linguagem descrita se representados em tipo fixo (e.g., parênteses).&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! style=&amp;quot;width: 140px; font-weight: normal;&amp;quot; | &#039;&#039;ficheiro&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;programa-principal&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;declaração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;tipo&#039;&#039; &#039;&#039;identificador&#039;&#039; [ &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| [ &#039;&#039;qualificador&#039;&#039; ] [ &#039;&#039;&#039;auto&#039;&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;=&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 150px; font-weight: normal;&amp;quot; | &#039;&#039;programa-principal&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;begin&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;end&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
|  [ &#039;&#039;qualificador&#039;&#039; ] &#039;&#039;identificador&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;variáveis&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;&#039;-&amp;gt;&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;variáveis&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;variável&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;int&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;real&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;string&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;void&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;[&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;]&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipo-de-função&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &#039;&#039;&#039;&amp;lt;&#039;&#039;&#039; &#039;&#039;tipos&#039;&#039; &#039;&#039;&#039;&amp;gt;&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;tipos&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;tipo&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;{&#039;&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;declaração&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; &#039;&#039;&#039;}&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;expressões&#039;&#039; &#039;&#039;&#039;!!&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;stop&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;next&#039;&#039;&#039; [ &#039;&#039;literal-inteiro&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;&#039;return&#039;&#039;&#039; [ &#039;&#039;expressão&#039;&#039; ] &#039;&#039;&#039;;&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;instrução-condicional&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;instrução-de-iteração&#039;&#039; &amp;lt;math&amp;gt;|&amp;lt;/math&amp;gt; &#039;&#039;bloco&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-condicional&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;if&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt;  &#039;&#039;&#039;elif&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt; [ &#039;&#039;&#039;else&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039; ]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;instrução-de-iteração&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;while&#039;&#039;&#039; &#039;&#039;&#039;(&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &#039;&#039;&#039;)&#039;&#039;&#039; &#039;&#039;instrução&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; | &#039;&#039;expressões&#039;&#039;&lt;br /&gt;
! style=&amp;quot;width: 50px; font-weight: normal;&amp;quot; |&amp;lt;math&amp;gt;\rightarrow&amp;lt;/math&amp;gt;&lt;br /&gt;
| &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\langle&amp;lt;/math&amp;gt; &#039;&#039;&#039;,&#039;&#039;&#039; &#039;&#039;expressão&#039;&#039; &amp;lt;math&amp;gt;\rangle&amp;lt;/math&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tipos, identificadores, literais e definição de expressões ==&lt;br /&gt;
&lt;br /&gt;
Algumas definições foram omitidas da gramática: tipos de dados. qualificadores e variável (ver [[#Declarações de variáveis|declarações de variáveis]]), identificador (ver [[#Identificadores (nomes)|identificadores]]), literal (ver [[#Literais|literais]]); expressão (ver [[#Expressões|expressões]]). &amp;lt;!--Note-se que &#039;&#039;função&#039;&#039; é qualquer especificação de função (corpo ou ponteiro com o tipo apropriado). Neste sentido, as funções contam como expressões primitivas.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Quanto a tipos de dados, &#039;&#039;&#039;int&#039;&#039;&#039; designa valores inteiros, &#039;&#039;&#039;real&#039;&#039;&#039; designa valores reais, &#039;&#039;&#039;string&#039;&#039;&#039; designa cadeias de caracteres. Os ponteiros são tipos compostos por um tipo entre parênteses rectos, e.g., &#039;&#039;&#039;[int]&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Os tipos funcionais são definidos a partir dos tipos de dados anteriormente descritos e do tipo especial &#039;&#039;&#039;void&#039;&#039;&#039; (ver a seguir). O tipo é indicado com o formato indicado na gramática, i.e., tipo de retorno seguido dos tipos dos argumentos (zero ou mais separados por vírgulas). Estes tipos servem para declarar símbolos de função sem as definir.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Um ponteiro declarado com um tipo de função indica o endereço da função correspondente. Estes ponteiros não suportam aritmética de ponteiros.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
O tipo &#039;&#039;&#039;void&#039;&#039;&#039; apenas pode ser usado para indicar a ausência de retorno ou para declarar um ponteiro genérico. Neste caso, o aninhamento é irrelevante, i.e., &#039;&#039;&#039;[void]&#039;&#039;&#039; e &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[void]]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; são equivalentes. Um ponteiro deste tipo é compatível com todos os outros tipos de ponteiros. A aritmética de ponteiros decrementa/incrementa em uma unidade o valor de um ponteiro do tipo &#039;&#039;&#039;[void]&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Left-values ==&lt;br /&gt;
&lt;br /&gt;
Os &#039;&#039;left-values&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
== Ficheiros ==&lt;br /&gt;
&lt;br /&gt;
Um ficheiro é designado por principal se contiver a função principal (onde se inicia o programa).&lt;br /&gt;
&lt;br /&gt;
== Declaração de variáveis ==&lt;br /&gt;
&lt;br /&gt;
Uma declaração de variável indica sempre um tipo de dados (implícito ou explícito) e um identificador.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
&lt;br /&gt;
* Inteiro: &#039;&#039;&#039;int i&#039;&#039;&#039;&lt;br /&gt;
* Real: &#039;&#039;&#039;real r&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres: &#039;&#039;&#039;string s&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro para inteiro: &#039;&#039;&#039;[int] p1&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para real: &#039;&#039;&#039;[real] p2&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;double*&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para cadeia de caracteres: &#039;&#039;&#039;[string] p3&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;char**&#039;&#039;&#039; em C)&lt;br /&gt;
* Ponteiro para ponteiro para inteiro: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[int]]&amp;lt;/nowiki&amp;gt; p4&#039;&#039;&#039; (semelhante a &#039;&#039;&#039;int**&#039;&#039;&#039; em C)&lt;br /&gt;
&lt;br /&gt;
É possível usar o pseudo-tipo &#039;&#039;&#039;auto&#039;&#039;&#039; se a declaração tiver um valor inicial: neste caso, o tipo é o do valor inicial.&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
* Variável inteira: &#039;&#039;&#039;auto i = 1&#039;&#039;&#039;&lt;br /&gt;
* Variável real: &#039;&#039;&#039;auto f = 2.0&#039;&#039;&#039;&lt;br /&gt;
* etc.&lt;br /&gt;
&lt;br /&gt;
== Símbolos globais ==&lt;br /&gt;
&lt;br /&gt;
Por omissão, os símbolos são privados a um módulo, não podendo ser importados por outros módulos.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;public&#039;&#039;&#039; permite declarar um identificador como público, tornando-o acessível a partir de outros módulos. Quando usado com a palavra-chave &#039;&#039;&#039;auto&#039;&#039;&#039;, esta é opcional. Note-se que a declaração de uma variável tem de ter sempre, ou o qualificador, ou o tipo, podendo estar ambos presentes.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;forward&#039;&#039;&#039; permite declarar num módulo variáveis ou funções definidas noutros módulos. Neste caso, não pode ser especificado o valor inicial das variáveis, pelo que não é possível o uso de &#039;&#039;&#039;auto&#039;&#039;&#039; em conjunto com &#039;&#039;&#039;forward&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A palavra-chave &#039;&#039;&#039;extern&#039;&#039;&#039; deve ser usada para declarar símbolos de função com tipos diferentes dos dos nativos da da linguagem P6, e.g. para importar funções definidas em C. Além de poderem ser usados para chamar as funções que designam, os símbolos assim declarados podem ser utilizados com valores convertidos de forma apropriada.&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Declarar variável privada ao módulo: &#039;&#039;&#039;real r1 = 22.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public real r2 = 7.0&#039;&#039;&#039;&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public auto r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Declarar variável pública: &#039;&#039;&#039;public r2 = 7.0&#039;&#039;&#039; (igual à anterior)&lt;br /&gt;
* Usar definição externa de variável pública: &#039;&#039;&#039;forward real r2&#039;&#039;&#039;&lt;br /&gt;
* Declarar função (nativa P6) definida externamente: &#039;&#039;&#039;forward int&amp;lt;int&amp;gt; factorial&#039;&#039;&#039;&lt;br /&gt;
* Declarar função definida noutra linguagem (e.g. em C): &#039;&#039;&#039;extern [void]&amp;lt;int&amp;gt; malloc&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Inicialização ==&lt;br /&gt;
&lt;br /&gt;
Quando existe, é a designação do objecto que segue o símbolo &#039;&#039;&#039;=&#039;&#039;&#039;: inteiro, real, cadeia de caracteres, ou 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.&amp;lt;!-- A associação de valores funcionais a variáveis pode ser realizada quando os tipos forem covariantes. As cadeias de caracteres são (possivelmente) inicializadas com uma lista não nula de valores sem separadores.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A palavra &#039;&#039;&#039;auto&#039;&#039;&#039; pode ser usada em lugar do tipo para declarar uma variável. Quando usada, o tipo da variável é inferido a partir do valor inicial (nestes casos, o valor inicial é obrigatório).&lt;br /&gt;
&lt;br /&gt;
Exemplos:&lt;br /&gt;
* Inteiro (literal): &#039;&#039;&#039;int i = 3&#039;&#039;&#039;&lt;br /&gt;
* Inteiro (expressão): &#039;&#039;&#039;int i = j + 1&#039;&#039;&#039;&lt;br /&gt;
* Real (literal): &#039;&#039;&#039;real r = 3.2&#039;&#039;&#039;&lt;br /&gt;
* Real (expressão): &#039;&#039;&#039;real r = i - 2.5&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literal): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Cadeia de caracteres (literais): &#039;&#039;&#039;string s = &amp;quot;olá&amp;quot; &amp;quot;mãe&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (literal): &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[[real]]] p&amp;lt;/nowiki&amp;gt; = null&#039;&#039;&#039;&lt;br /&gt;
* Ponteiro (expressão): &#039;&#039;&#039;[int] p = q + 1&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;!--* Função:&lt;br /&gt;
 int&amp;lt;int&amp;gt; f1&lt;br /&gt;
 int&amp;lt;real&amp;gt; g1&lt;br /&gt;
 real&amp;lt;int&amp;gt; g2&lt;br /&gt;
 int&amp;lt;int&amp;gt; f2 = f1  // ok: mesmo tipo&lt;br /&gt;
 f2 = g1 // ok: tipos covariantes&lt;br /&gt;
 f2 = g2 // ERRADO&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Funções =&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Declaração ==&lt;br /&gt;
&lt;br /&gt;
As funções têm um nome que é também o endereço dessa função. O tipo de retorno de uma função que não produz valores de retorno é &#039;&#039;&#039;void&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
As funções que recebam argumentos devem indicá-los no cabeçalho. Funções sem argumentos definem um cabeçalho vazio. Os qualificadores de exportação/importação &#039;&#039;&#039;public&#039;&#039;&#039; ou &#039;&#039;&#039;forward&#039;&#039;&#039; (ver símbolos globais) podem ser aplicados às funções, mas não é possível aplicá-los às declarações dos argumentos de uma função. Não é possível especificar valores por omissão para os argumentos de uma função, nem para o valor de retorno.&lt;br /&gt;
&lt;br /&gt;
A declaração de um ponteiro para uma função (ou, de forma equivalente, do seu nome) é utilizada para caracterizar 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). &amp;lt;!--Caso a declaração tenha corpo, define-se uma nova função.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Invocação ==&lt;br /&gt;
&lt;br /&gt;
Uma função pode ser invocada através do seu nome. &amp;lt;!--ou de um ponteiro do tipo apropriado que refira essa função (ponteiro não nulo). O símbolo &#039;&#039;&#039;@&#039;&#039;&#039; pode ser usado dentro da própria função para efectuar uma invocação recursiva. Não é possível o uso de &#039;&#039;&#039;@&#039;&#039;&#039; no programa principal.--&amp;gt;&lt;br /&gt;
Se existirem argumentos, na invocação da função, o nome é 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 menos de conversões implícitas). A ordem dos parâmetros actuais deverá ser a mesma dos argumentos formais da função a ser invocada.&lt;br /&gt;
&lt;br /&gt;
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. Note que o retorno de entidades com dimensão superior a 64 bits deve fazer-se através da reserva de espaço para o retorno no chamador e passando um ponteiro para esse espaço como primeiro argumento do chamado.&lt;br /&gt;
&lt;br /&gt;
== Corpo ==&lt;br /&gt;
&lt;br /&gt;
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 de exportação (&#039;&#039;&#039;public&#039;&#039;&#039;) ou de importação (&#039;&#039;&#039;forward&#039;&#039;&#039; ou &#039;&#039;&#039;extern&#039;&#039;&#039;) (ver [[#Símbolos globais|símbolos globais]]) dentro do corpo de uma função.&lt;br /&gt;
&lt;br /&gt;
Uma instrução &#039;&#039;&#039;return&#039;&#039;&#039; causa a interrupção da função. O valor devolvido por uma função, através de expressão usada como argumento da instrução &#039;&#039;&#039;return&#039;&#039;&#039;, deve ser do tipo declarado no cabeçalho da função. Ver casos especiais acima.&lt;br /&gt;
&lt;br /&gt;
É um erro especificar um valor de retorno se a função for declarada como não retornando um valor (indicada como &#039;&#039;&#039;void&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Qualquer bloco (usado, por exemplo, numa instrução condicional ou de iteração) pode definir variáveis locais. &amp;lt;!--, cujos valores podem ser outras funções. Funções definidas dentro de um bloco não têm acesso às variáveis em contexto na função actual onde ocorrem.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Função principal e execução de programas ==&lt;br /&gt;
&lt;br /&gt;
Um programa é a sequência de instruções que seguem as declarações globais num ficheiro, delimitadas pelas palavras-chave &#039;&#039;&#039;begin&#039;&#039;&#039; e &#039;&#039;&#039;end&#039;&#039;&#039;. Esta sequência forma o que em algumas linguagens se chama a função principal. Os argumentos com que o programa foi chamado podem ser obtidos através de funções &#039;&#039;&#039;argc&#039;&#039;&#039; (devolve o número de argumentos); &#039;&#039;&#039;argv&#039;&#039;&#039; (devolve o n-ésimo argumento como uma cadeia de caracteres, com n&amp;gt;0); e &#039;&#039;&#039;envp&#039;&#039;&#039; (devolve a n-ésima variável de ambiente como uma cadeia de caracteres, com n&amp;gt;0). Apenas um dos módulos do programa pode definir a função principal, i.e., se existirem vários módulos, apenas um deles pode conter mais do que declarações de variáveis globais.&lt;br /&gt;
&lt;br /&gt;
 extern int&amp;lt;&amp;gt; argc&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; argv&lt;br /&gt;
 extern string&amp;lt;int&amp;gt; envp&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
= Instruções =&lt;br /&gt;
&lt;br /&gt;
Excepto quando indicado, as instruções são executadas em sequência.&lt;br /&gt;
&lt;br /&gt;
== Blocos ==&lt;br /&gt;
&lt;br /&gt;
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 definir funções dentro de blocos, mas é possível declarar ponteiros de função locais.&lt;br /&gt;
&lt;br /&gt;
A visibilidade das variáveis é limitada ao bloco em que foram declaradas. As entidades declaradas podem ser directamente utilizadas em sub-blocos ou passadas como argumentos para funções chamadas dentro do bloco. Caso os identificadores usados para definir as variáveis locais já estejam a ser utilizados para definir outras entidades ao alcance do bloco, o novo identificador passa a referir uma nova entidade definida no bloco até que ele termine (a entidade previamente definida continua a existir, mas não pode ser directamente referida pelo seu nome). Esta regra é também válida relativamente a&lt;br /&gt;
argumentos de funções (ver corpo das funções).&lt;br /&gt;
&lt;br /&gt;
== Instrução condicional ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento semelhante ao da instrução &#039;&#039;&#039;if-else&#039;&#039;&#039; em C. As partes correspondentes a &#039;&#039;&#039;elif&#039;&#039;&#039; comportam-se como encadeamentos de instruções condicionais na parte &#039;&#039;&#039;else&#039;&#039;&#039; de um &#039;&#039;&#039;if-else&#039;&#039;&#039; à la C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de iteração ==&lt;br /&gt;
&lt;br /&gt;
Esta instrução tem comportamento idêntico ao da instrução &#039;&#039;&#039;while&#039;&#039;&#039; em C.&lt;br /&gt;
&lt;br /&gt;
== Instrução de terminação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;stop&#039;&#039;&#039; termina o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;break&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de continuação ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;next&#039;&#039;&#039; reinicia o n-ésimo ciclo mais interior em que a instrução se encontrar (quando o argumento é omitido, assume-se &#039;&#039;&#039;n=1&#039;&#039;&#039;), tal como a instrução &#039;&#039;&#039;continue&#039;&#039;&#039; em C. Esta instrução só pode existir dentro de um ciclo, sendo a última instrução do seu bloco.&lt;br /&gt;
&lt;br /&gt;
{{Suggestion|Note-se que, tal como na restante aritmética de ponteiros, o valor inteiro, neste caso, corresponde a uma entidade binária com 32 bits.}}&lt;br /&gt;
&lt;br /&gt;
== Instrução de retorno ==&lt;br /&gt;
&lt;br /&gt;
A instrução &#039;&#039;&#039;return&#039;&#039;&#039;, se existir, é a última instrução do seu bloco. Ver comportamento na [[#Corpo|descrição do corpo de uma função]].&lt;br /&gt;
&lt;br /&gt;
== Expressões como instruções ==&lt;br /&gt;
&lt;br /&gt;
As expressões utilizadas como instruções são sempre avaliadas, mesmo que não produzam efeitos secundários.&lt;br /&gt;
&lt;br /&gt;
== Instruções de impressão ==&lt;br /&gt;
&lt;br /&gt;
As notações &#039;&#039;&#039;!&#039;&#039;&#039; e &#039;&#039;&#039;!!&#039;&#039;&#039; podem ser utilizadas para apresentar valores na saída do programa. A primeira forma apresenta os valores sem mudar de linha; a segunda forma apresenta os valores mudando de linha depois de os apresentar a todos. Quando existe mais de uma expressão, as várias expressões são apresentadas sem separação. Valores numéricos (inteiros ou reais) são impressos em decimal. As cadeias de caracteres são impressas na codificação nativa. Ponteiros não podem ser impressos.&lt;br /&gt;
&lt;br /&gt;
= Expressões =&lt;br /&gt;
&lt;br /&gt;
Uma expressão é uma representação algébrica de uma quantidade: todas as expressões têm um tipo e devolvem um valor.&lt;br /&gt;
&lt;br /&gt;
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]].&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
 {|&lt;br /&gt;
| &#039;&#039;&#039;Tipo de Expressão&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operadores&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Associatividade&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Operandos&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Semântica&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| primária&lt;br /&gt;
| &#039;&#039;&#039;( ) [ ]&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Parênteses curvos|parênteses curvos]], [[#Indexação|indexação]], [[#Reserva de memória|reserva de memória]]&lt;br /&gt;
|-&lt;br /&gt;
| unária&lt;br /&gt;
| &#039;&#039;&#039;+ - ?&#039;&#039;&#039;&lt;br /&gt;
| não associativos&lt;br /&gt;
| -&lt;br /&gt;
| [[#Identidade e simétrico|identidade e simétrico]], [[#Expressão de indicação de posição|indicação de posição]]&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;não&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;~&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | não associativo&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: negação&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | multiplicativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;* / %&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | aditiva&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;+ -&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C (% é apenas para inteiros), mas para entidades ternárias: se envolverem ponteiros, calculam: (i) deslocamentos, i.e., um dos operandos deve ser do tipo ponteiro e o outro do tipo inteiro (binário de 32 bits); (ii) diferenças de ponteiros, i.e., apenas quando se aplica o operador &#039;&#039;&#039;-&#039;&#039;&#039; a dois ponteiros do mesmo tipo (o resultado é o número de objectos do tipo apontado entre eles, representado como um valor inteiro ternário de 64 bits). Se a memória não for contígua, o resultado é indefinido.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | comparativa&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt; &amp;gt; &amp;lt;= &amp;gt;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | igualdade&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;== !=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros, reais, ponteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | análoga à do C, mas para entidades ternárias&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;e&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for falso.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &amp;quot;ou&amp;quot; lógico&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;||&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da esquerda para a direita&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | inteiros&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | Lógica de Kleene: o 2º argumento só é avaliado se o 1º não for verdadeiro.&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | atribuição&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | &#039;&#039;&#039;=&#039;&#039;&#039;&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | da direita para a esquerda&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | todos os tipos&lt;br /&gt;
! style=&amp;quot;vertical-align: top; font-weight: normal;&amp;quot; | O valor da expressão do lado direito do operador é guardado na posição indicada pelo &#039;&#039;left-value&#039;&#039; (operando esquerdo do operador). Podem ser atribuídos valores inteiros a &#039;&#039;left-values&#039;&#039; reais (conversão automática). Nos outros casos, ambos os tipos têm de concordar. O literal &#039;&#039;&#039;null&#039;&#039;&#039; é compatível com todos os tipos de ponteiros.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Expressões primitivas ==&lt;br /&gt;
&lt;br /&gt;
As [[#Literais|expressões literais]] e a [[#Invocação|invocação de funções]] foram definidas acima.&lt;br /&gt;
&lt;br /&gt;
=== Identificadores ===&lt;br /&gt;
&lt;br /&gt;
Um identificador é uma expressão se tiver sido declarado. Um identificador pode denotar uma variável.&lt;br /&gt;
&lt;br /&gt;
Um identificador é o caso mais simples de um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;, ou seja, uma entidade que pode ser utilizada no lado esquerdo (&#039;&#039;left&#039;&#039;) de uma atribuição.&lt;br /&gt;
&lt;br /&gt;
=== Leitura ===&lt;br /&gt;
&lt;br /&gt;
A operação de leitura de um valor inteiro ou real pode ser efectuado pela expressão indicada pela palavra-chave &#039;&#039;&#039;input&#039;&#039;&#039;, que devolve o valor lido, de acordo com o tipo esperado (inteiro ou real). Caso se use como argumento dos operadores de impressão ou noutras situações que permitam vários tipos (e.g. &#039;&#039;&#039;!&#039;&#039;&#039; ou &#039;&#039;&#039;!!&#039;&#039;&#039;), deve ser lido um inteiro.&lt;br /&gt;
&lt;br /&gt;
Exemplos:  &#039;&#039;&#039;a = input&#039;&#039;&#039; (leitura para &#039;&#039;&#039;a&#039;&#039;&#039;), &#039;&#039;&#039;f(input)&#039;&#039;&#039; (leitura para argumento de função), &#039;&#039;&#039;input!!&#039;&#039;&#039; (leitura e impressão).&lt;br /&gt;
&lt;br /&gt;
=== Parênteses curvos ===&lt;br /&gt;
&lt;br /&gt;
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 &#039;&#039;left-value&#039;&#039; (ver também a [[#Indexação|expressão de indexação]]).&lt;br /&gt;
&amp;lt;!--=== Funções ===&lt;br /&gt;
&lt;br /&gt;
As funções (ponteiros ou o seu código: não confundir com chamadas a funções) podem ser usadas como expressões tipificadas como funções, i.e., ponteiros para funções (mesmo quando não se usa explicitamente um ponteiro).&lt;br /&gt;
&lt;br /&gt;
Exemplo:&lt;br /&gt;
&lt;br /&gt;
 f1(int i) -&amp;gt; int { return i + 1; }&lt;br /&gt;
 f2(int i) -&amp;gt; int { return i * 2; }&lt;br /&gt;
&lt;br /&gt;
 g(int n, int&amp;lt;int&amp;gt; fun) -&amp;gt; int { return fun(n); }&lt;br /&gt;
 &lt;br /&gt;
 begin&lt;br /&gt;
   g(3, f1)!!  // escreve 4&lt;br /&gt;
   g(3, f2)!!  // escreve 6&lt;br /&gt;
 end&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expressões resultantes de avaliação de operadores ==&lt;br /&gt;
&lt;br /&gt;
=== Indexação de ponteiros ===&lt;br /&gt;
&lt;br /&gt;
A indexação de ponteiros devolve o valor de uma posição de memória indicada por um ponteiro. Consiste em uma expressão ponteiro seguida do índice entre parênteses rectos. O resultado de uma indexação de ponteiros é um &#039;&#039;[[#Left-values|left-value]]&#039;&#039;. Não é possível indexar ponteiros que designem funções.&lt;br /&gt;
&lt;br /&gt;
Exemplo (acesso à posição 0 da zona de memória indicada por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;p[0]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Identidade e simétrico ===&lt;br /&gt;
&lt;br /&gt;
Os operadores identidade (&#039;&#039;&#039;+&#039;&#039;&#039;) e simétrico (&#039;&#039;&#039;-&#039;&#039;&#039;) aplicam-se a inteiros e reais. Têm o mesmo significado que em análogo às operações correspondentes em C, mas operam sobre grandezas ternárias.&lt;br /&gt;
&lt;br /&gt;
=== Reserva de memória ===&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Exemplo (reserva vector com 5 reais, apontados por &#039;&#039;&#039;p&#039;&#039;&#039;): &#039;&#039;&#039;[real] p = [5]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de indicação de posição ===&lt;br /&gt;
&lt;br /&gt;
O operador sufixo &#039;&#039;&#039;?&#039;&#039;&#039; aplica-se a &#039;&#039;left-values&#039;&#039;, retornando o endereço (com o tipo ponteiro) correspondente.&lt;br /&gt;
&lt;br /&gt;
Exemplo (indica o endereço de &#039;&#039;&#039;a&#039;&#039;&#039;): &#039;&#039;&#039;a?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Expressão de dimensão ===&lt;br /&gt;
&lt;br /&gt;
O operador &#039;&#039;&#039;sizeof&#039;&#039;&#039; tem um único argumento e aplica-se a expressões, retornando a dimensão correspondente em bytes.&lt;br /&gt;
&lt;br /&gt;
Exemplo: &#039;&#039;&#039;sizeof(a)&#039;&#039;&#039; (dimensão de &#039;&#039;&#039;a&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
= Exemplos e Testes =&lt;br /&gt;
&lt;br /&gt;
Os exemplos abaixo não são exaustivos e não ilustram todos os aspectos da linguagem.&lt;br /&gt;
&lt;br /&gt;
Estão ainda disponíveis outros [https://gitlab.rnl.tecnico.ulisboa.pt/leic-a-co26/eval/co26 pacotes de testes].&lt;br /&gt;
&lt;br /&gt;
O seguinte exemplo ilustra um programa com dois módulos: um que define a função &#039;&#039;&#039;factorial&#039;&#039;&#039; e outro que define a função principal.&lt;br /&gt;
&lt;br /&gt;
Definição da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;factorial.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
public factorial(int n) -&amp;gt; int {&lt;br /&gt;
  if (n &amp;gt; 1) &lt;br /&gt;
    return n * factorial(n - 1);&lt;br /&gt;
  else &lt;br /&gt;
    return 1;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exemplo da utilização da função &#039;&#039;&#039;factorial&#039;&#039;&#039; no ficheiro &#039;&#039;&#039;main.p6&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
// external builtin functions (non-P6)&lt;br /&gt;
extern int&amp;lt;&amp;gt; argc;&lt;br /&gt;
extern string&amp;lt;int&amp;gt; argv;&lt;br /&gt;
extern int&amp;lt;string&amp;gt; atoi;&lt;br /&gt;
&lt;br /&gt;
// external user functions (P6)&lt;br /&gt;
forward int&amp;lt;int&amp;gt; factorial;&lt;br /&gt;
&lt;br /&gt;
// the main function&lt;br /&gt;
begin&lt;br /&gt;
  auto value = 1;&lt;br /&gt;
  &amp;quot;Teste para a função factorial.&amp;quot;!!&lt;br /&gt;
  if (argc() == 2) {&lt;br /&gt;
    string s = argv(1);&lt;br /&gt;
    value = atoi(s);&lt;br /&gt;
  }&lt;br /&gt;
  value, &amp;quot;! é &amp;quot;, factorial(value)!!&lt;br /&gt;
  return 0;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Como compilar:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
p6 --target asm factorial.p6&lt;br /&gt;
p6 --target asm main.p6&lt;br /&gt;
yasm -felf32 factorial.asm&lt;br /&gt;
yasm -felf32 main.asm&lt;br /&gt;
ld -melf_i386 -o main factorial.o main.o -lrts&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Omissões e Erros =&lt;br /&gt;
&lt;br /&gt;
Casos omissos e erros serão corrigidos em futuras versões do manual de referência.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category: Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Avalia%C3%A7%C3%A3o_do_Projecto_(%C3%89poca_Normal)&amp;diff=17743</id>
		<title>Compiladores/Projecto de Compiladores/Avaliação do Projecto (Época Normal)</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Avalia%C3%A7%C3%A3o_do_Projecto_(%C3%89poca_Normal)&amp;diff=17743"/>
		<updated>2026-05-06T08:22:41Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Teste Prático */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20222023}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
== Método de Avaliação do Projecto ==&lt;br /&gt;
&lt;br /&gt;
A avaliação relativa à componente do Projecto processa-se em várias fases:&lt;br /&gt;
&lt;br /&gt;
* [[#Entrega Zero (inicial) - Projecto Base|Entrega Zero (inicial): projecto base]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Entrega Intermédia - Gerador de XML|Entrega Intermédia: gerador de XML]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Entrega Final - Compilador Completo|Entrega Final: compilador completo]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Teste Prático|Teste prático]] (&#039;&#039;&#039;obrigatório&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--O Projecto (trabalho conducente às entregas acima mencionadas e abaixo descritas) é realizado individualmente, durante o período estabelecido.--&amp;gt;&lt;br /&gt;
O Projecto (trabalho conducente às entregas acima mencionadas e abaixo descritas) é realizado por grupos de, no máximo, 2 (dois) elementos, durante o período estabelecido.&lt;br /&gt;
&lt;br /&gt;
O Teste Prático é realizado individualmente, em data e local a agendar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A não realização de componentes obrigatórias tem como consequência a classificação de zero valores na componente de projecto e exclusão da avaliação em época normal.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;TODAS AS ENTREGAS SÃO REALIZADAS ATÉ ÀS 12:00 (&amp;quot;meio-dia&amp;quot;) DAS RESPECTIVAS DATAS&#039;&#039;&#039;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;TODAS AS ENTREGAS SÃO OBRIGATÓRIAS E SÃO REALIZADAS ATÉ ÀS 17:00 DAS RESPECTIVAS DATAS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Cálculo da Nota do Projecto e Condições de Aprovação ==&lt;br /&gt;
&lt;br /&gt;
Componentes de avaliação:&lt;br /&gt;
* &#039;&#039;&#039;PRJ&#039;&#039;&#039; - nota final do projecto&lt;br /&gt;
* &#039;&#039;&#039;E0&#039;&#039;&#039; - nota da entrega &amp;quot;zero&amp;quot;&lt;br /&gt;
* &#039;&#039;&#039;EI&#039;&#039;&#039; - nota da entrega intermédia&lt;br /&gt;
* &#039;&#039;&#039;EF&#039;&#039;&#039; - nota da entrega final&lt;br /&gt;
* &#039;&#039;&#039;TP&#039;&#039;&#039; - nota do teste prático&lt;br /&gt;
&lt;br /&gt;
A nota do teste prático condiciona a distância ao mínimo entre as notas do teste prático e a do projecto: desde um mínimo de 12.5% de acréscimo à menor das duas (abaixo de 7.5 valores no TP), até um máximo de 25% (para 20 valores no TP). O acréscimo é linear entre 7.5 e 20. &lt;br /&gt;
&lt;br /&gt;
Ou seja:&lt;br /&gt;
* &#039;&#039;&#039;PRJ = min(E0+EI+EF, TP) + | TP - E0 - EI - EF | * max(12.5, TP+5) / 100&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Condições necessárias para aprovação à disciplina (necessárias todas):&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;PRJ &amp;gt;= 9.5&#039;&#039;&#039; (sem arredondamento)&lt;br /&gt;
* &#039;&#039;&#039;PRJ != NA&#039;&#039;&#039; &lt;br /&gt;
* &#039;&#039;&#039;TP &amp;gt; 0&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;TP != NA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Zero (inicial) - Projecto Base ==&lt;br /&gt;
&lt;br /&gt;
A Entrega &amp;quot;Zero&amp;quot; avalia o estado do projecto relativamente à concepção dos nós que representam os conceitos da linguagem (sem ser necessário tratar ainda do seu reconhecimento ou processamento).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 2 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Não serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Nesta fase, além da estrutura básica do compilador, todas as classes dos nós da linguagem, assim como os esqueletos dos &amp;quot;visitors&amp;quot; (xml_writer, postfix_writer, etc.) devem estar implementados. Não é ainda necessário ter implementado nenhum código de análise lexical, sintáctica ou semântica.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega &amp;quot;zero&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Considerando que é um passo crucial na concepção do projecto, a não realização desta entrega conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente exclusão da avaliação da disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Intermédia - Gerador de XML ==&lt;br /&gt;
&lt;br /&gt;
A Entrega Intermédia avalia o estado do projecto relativamente a um mínimo de funcionalidade.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 6 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Não serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega intermédia]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização da Entrega Intermédia conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Final - Compilador Completo ==&lt;br /&gt;
&lt;br /&gt;
A Entrega Final pressupõe que todo o projecto foi implementado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 12 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Os testes correspondem a uma série de programas que deverão ser compilados pelo resultado do projecto de cada grupo e cuja execução deve corresponder a um conjunto de resultados padrão.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega final]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização da Entrega Final conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Teste Prático ==&lt;br /&gt;
&lt;br /&gt;
O Teste Prático consiste em fazer pequenas alterações/extensões ao projecto descrito no enunciado. O teste é realizado com base na implementação submetida para a avaliação correspondente à entrega final.&lt;br /&gt;
&lt;br /&gt;
Este teste avalia o conhecimento do aluno relativamente ao projecto entregue, assim como a sua capacidade de realizar alterações ao código do projecto.&lt;br /&gt;
&lt;br /&gt;
O teste prático é como uma discussão de projecto, pelo que não existem repescagens como nos testes escritos. Alunos que faltem ao teste prático estão automaticamente reprovados à disciplina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização do Teste Prático conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Concretamente, o teste prático corresponde à resolução uma pergunta que aborda os seguintes três tópicos:&lt;br /&gt;
análise lexical;&lt;br /&gt;
análise sintáctica; e&lt;br /&gt;
análise semântica e geração de código.&lt;br /&gt;
Cada tópico pode ser resolvido com mais ou menos profundidade (embora isso implique funcionamento possivelmente deficiente a jusante) e será avaliado independentemente.&lt;br /&gt;
&lt;br /&gt;
Ver também [[Compiladores/Projecto_de_Compiladores/Teste_Prático_(Época_Normal)|calendário do teste prático]].&lt;br /&gt;
&lt;br /&gt;
== Considerações Adicionais sobre a Avaliação do Projecto ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;O projecto deverá ser desenvolvido atempadamente ao longo do semestre.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
As versões intermédias registadas no Gitlab poderão ser testadas, pelo que deverão ser periodicamente actualizadas. O projecto é constituído por um projecto Gitlab designado pelo número do grupo que o executa. O repositório GIT disponibilizado já contém uma versão vazia do projecto. Apenas os ficheiros registados no projecto Gitlab serão considerados na avaliação.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Não serão consideradas quaisquer alterações aos ficheiros disponibilizados: eventuais cópias desses ficheiros serão automaticamente substituídas durante a avaliação da funcionalidade do código submetido.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A avaliação executa testes automáticos aos programas na linguagem a implementar: caso os testes falhem por causas imputáveis ao grupo, a nota reflectirá apenas os testes bem sucedidos. Para tal, o compilador deve chamar-se &#039;&#039;&#039;p6&#039;&#039;&#039; e não &amp;quot;P6&amp;quot;, &amp;quot;proj&amp;quot;, &amp;quot;compiladores&amp;quot;, &amp;quot;projecto&amp;quot;, ou outro nome (a makefile fornecida já faz este trabalho). As restantes componentes da nota são obtidas pela análise do código e resultado do teste prático (realizado individualmente). O código é avaliado quanto à sua correcção, simplicidade, extensibilidade e legibilidade: devem existir comentários das partes mais complexas, mas não devem ser excessivos nem óbvios (diminuem a legibilidade), nem muito escassos (impedem a compreensão). O teste prático avalia a capacidade de efectuar alterações ao código entregue.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qualquer alteração à especificação da linguagem é penalizada, mesmo que possa ser entendida como um melhoramento.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Notar que o facto de os testes automáticos terem sido superados não reflecte a qualidade do código, quer do ponto de vista de engenharia de software, quer do ponto de vista da correcta aplicação dos princípios leccionados na disciplina. No entanto, a funcionalidade do compilador final também é importante, pelo que &#039;&#039;&#039;é preferível um compilador que realize, correctamente, apenas parte da funcionalidade a um quase completo mas que nem sequer compila ou que não gera nenhum programa correcto&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Compromisso de Honra ==&lt;br /&gt;
&lt;br /&gt;
A entrega de quaisquer trabalhos pressupõe o compromisso de honra que foram realizados pelos autores referenciados. A quebra deste compromisso, i.e., a tentativa de apropriação de trabalhos alheios, terá como consequência a reprovação de todos os alunos envolvidos (incluindo os que possibilitaram a ocorrência) no ano lectivo actual, sem prejuízo de acções disciplinares previstas pelo IST.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Avalia%C3%A7%C3%A3o_do_Projecto_(%C3%89poca_Normal)&amp;diff=17742</id>
		<title>Compiladores/Projecto de Compiladores/Avaliação do Projecto (Época Normal)</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Avalia%C3%A7%C3%A3o_do_Projecto_(%C3%89poca_Normal)&amp;diff=17742"/>
		<updated>2026-05-06T08:21:07Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Entrega Final - Compilador Completo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20222023}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
== Método de Avaliação do Projecto ==&lt;br /&gt;
&lt;br /&gt;
A avaliação relativa à componente do Projecto processa-se em várias fases:&lt;br /&gt;
&lt;br /&gt;
* [[#Entrega Zero (inicial) - Projecto Base|Entrega Zero (inicial): projecto base]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Entrega Intermédia - Gerador de XML|Entrega Intermédia: gerador de XML]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Entrega Final - Compilador Completo|Entrega Final: compilador completo]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Teste Prático|Teste prático]] (&#039;&#039;&#039;obrigatório&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--O Projecto (trabalho conducente às entregas acima mencionadas e abaixo descritas) é realizado individualmente, durante o período estabelecido.--&amp;gt;&lt;br /&gt;
O Projecto (trabalho conducente às entregas acima mencionadas e abaixo descritas) é realizado por grupos de, no máximo, 2 (dois) elementos, durante o período estabelecido.&lt;br /&gt;
&lt;br /&gt;
O Teste Prático é realizado individualmente, em data e local a agendar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A não realização de componentes obrigatórias tem como consequência a classificação de zero valores na componente de projecto e exclusão da avaliação em época normal.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;TODAS AS ENTREGAS SÃO REALIZADAS ATÉ ÀS 12:00 (&amp;quot;meio-dia&amp;quot;) DAS RESPECTIVAS DATAS&#039;&#039;&#039;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;TODAS AS ENTREGAS SÃO OBRIGATÓRIAS E SÃO REALIZADAS ATÉ ÀS 17:00 DAS RESPECTIVAS DATAS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Cálculo da Nota do Projecto e Condições de Aprovação ==&lt;br /&gt;
&lt;br /&gt;
Componentes de avaliação:&lt;br /&gt;
* &#039;&#039;&#039;PRJ&#039;&#039;&#039; - nota final do projecto&lt;br /&gt;
* &#039;&#039;&#039;E0&#039;&#039;&#039; - nota da entrega &amp;quot;zero&amp;quot;&lt;br /&gt;
* &#039;&#039;&#039;EI&#039;&#039;&#039; - nota da entrega intermédia&lt;br /&gt;
* &#039;&#039;&#039;EF&#039;&#039;&#039; - nota da entrega final&lt;br /&gt;
* &#039;&#039;&#039;TP&#039;&#039;&#039; - nota do teste prático&lt;br /&gt;
&lt;br /&gt;
A nota do teste prático condiciona a distância ao mínimo entre as notas do teste prático e a do projecto: desde um mínimo de 12.5% de acréscimo à menor das duas (abaixo de 7.5 valores no TP), até um máximo de 25% (para 20 valores no TP). O acréscimo é linear entre 7.5 e 20. &lt;br /&gt;
&lt;br /&gt;
Ou seja:&lt;br /&gt;
* &#039;&#039;&#039;PRJ = min(E0+EI+EF, TP) + | TP - E0 - EI - EF | * max(12.5, TP+5) / 100&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Condições necessárias para aprovação à disciplina (necessárias todas):&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;PRJ &amp;gt;= 9.5&#039;&#039;&#039; (sem arredondamento)&lt;br /&gt;
* &#039;&#039;&#039;PRJ != NA&#039;&#039;&#039; &lt;br /&gt;
* &#039;&#039;&#039;TP &amp;gt; 0&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;TP != NA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Zero (inicial) - Projecto Base ==&lt;br /&gt;
&lt;br /&gt;
A Entrega &amp;quot;Zero&amp;quot; avalia o estado do projecto relativamente à concepção dos nós que representam os conceitos da linguagem (sem ser necessário tratar ainda do seu reconhecimento ou processamento).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 2 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Não serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Nesta fase, além da estrutura básica do compilador, todas as classes dos nós da linguagem, assim como os esqueletos dos &amp;quot;visitors&amp;quot; (xml_writer, postfix_writer, etc.) devem estar implementados. Não é ainda necessário ter implementado nenhum código de análise lexical, sintáctica ou semântica.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega &amp;quot;zero&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Considerando que é um passo crucial na concepção do projecto, a não realização desta entrega conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente exclusão da avaliação da disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Intermédia - Gerador de XML ==&lt;br /&gt;
&lt;br /&gt;
A Entrega Intermédia avalia o estado do projecto relativamente a um mínimo de funcionalidade.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 6 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Não serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega intermédia]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização da Entrega Intermédia conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Final - Compilador Completo ==&lt;br /&gt;
&lt;br /&gt;
A Entrega Final pressupõe que todo o projecto foi implementado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 12 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Os testes correspondem a uma série de programas que deverão ser compilados pelo resultado do projecto de cada grupo e cuja execução deve corresponder a um conjunto de resultados padrão.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega final]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização da Entrega Final conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Teste Prático ==&lt;br /&gt;
&lt;br /&gt;
O Teste Prático consiste em fazer pequenas alterações/extensões ao projecto descrito no enunciado. O teste é realizado com base na implementação submetida para a avaliação correspondente à entrega final.&lt;br /&gt;
&lt;br /&gt;
Este teste avalia o conhecimento do aluno relativamente ao projecto entregue, assim como a sua capacidade de realizar alterações ao código do projecto.&lt;br /&gt;
&lt;br /&gt;
O teste prático é como uma discussão de projecto, pelo que não existem repescagens como nos testes escritos. Alunos que faltem ao teste prático estão automaticamente reprovados à disciplina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização do Teste Prático conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Concretamente, o teste prático corresponde à resolução uma pergunta que aborda os seguintes três tópicos:&lt;br /&gt;
análise lexical;&lt;br /&gt;
análise sintáctica; e&lt;br /&gt;
análise semântica e geração de código.&lt;br /&gt;
Cada tópico pode ser resolvido com mais ou menos profundidade (embora isso implique funcionamento possivelmente deficiente a jusante) e será avaliado independentemente.&lt;br /&gt;
&lt;br /&gt;
== Considerações Adicionais sobre a Avaliação do Projecto ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;O projecto deverá ser desenvolvido atempadamente ao longo do semestre.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
As versões intermédias registadas no Gitlab poderão ser testadas, pelo que deverão ser periodicamente actualizadas. O projecto é constituído por um projecto Gitlab designado pelo número do grupo que o executa. O repositório GIT disponibilizado já contém uma versão vazia do projecto. Apenas os ficheiros registados no projecto Gitlab serão considerados na avaliação.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Não serão consideradas quaisquer alterações aos ficheiros disponibilizados: eventuais cópias desses ficheiros serão automaticamente substituídas durante a avaliação da funcionalidade do código submetido.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A avaliação executa testes automáticos aos programas na linguagem a implementar: caso os testes falhem por causas imputáveis ao grupo, a nota reflectirá apenas os testes bem sucedidos. Para tal, o compilador deve chamar-se &#039;&#039;&#039;p6&#039;&#039;&#039; e não &amp;quot;P6&amp;quot;, &amp;quot;proj&amp;quot;, &amp;quot;compiladores&amp;quot;, &amp;quot;projecto&amp;quot;, ou outro nome (a makefile fornecida já faz este trabalho). As restantes componentes da nota são obtidas pela análise do código e resultado do teste prático (realizado individualmente). O código é avaliado quanto à sua correcção, simplicidade, extensibilidade e legibilidade: devem existir comentários das partes mais complexas, mas não devem ser excessivos nem óbvios (diminuem a legibilidade), nem muito escassos (impedem a compreensão). O teste prático avalia a capacidade de efectuar alterações ao código entregue.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qualquer alteração à especificação da linguagem é penalizada, mesmo que possa ser entendida como um melhoramento.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Notar que o facto de os testes automáticos terem sido superados não reflecte a qualidade do código, quer do ponto de vista de engenharia de software, quer do ponto de vista da correcta aplicação dos princípios leccionados na disciplina. No entanto, a funcionalidade do compilador final também é importante, pelo que &#039;&#039;&#039;é preferível um compilador que realize, correctamente, apenas parte da funcionalidade a um quase completo mas que nem sequer compila ou que não gera nenhum programa correcto&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Compromisso de Honra ==&lt;br /&gt;
&lt;br /&gt;
A entrega de quaisquer trabalhos pressupõe o compromisso de honra que foram realizados pelos autores referenciados. A quebra deste compromisso, i.e., a tentativa de apropriação de trabalhos alheios, terá como consequência a reprovação de todos os alunos envolvidos (incluindo os que possibilitaram a ocorrência) no ano lectivo actual, sem prejuízo de acções disciplinares previstas pelo IST.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
	<entry>
		<id>https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Avalia%C3%A7%C3%A3o_do_Projecto_(%C3%89poca_Normal)&amp;diff=17741</id>
		<title>Compiladores/Projecto de Compiladores/Avaliação do Projecto (Época Normal)</title>
		<link rel="alternate" type="text/html" href="https://robots.hlt.inesc-id.pt/w/pt/index.php?title=Compiladores/Projecto_de_Compiladores/Avalia%C3%A7%C3%A3o_do_Projecto_(%C3%89poca_Normal)&amp;diff=17741"/>
		<updated>2026-05-06T08:20:22Z</updated>

		<summary type="html">&lt;p&gt;Root: /* Entrega Intermédia - Gerador de XML */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{PRJCompiladoreAvisosEN20252026}}&lt;br /&gt;
&amp;lt;!--{{PRJCompiladoreAvisosEE20222023}}--&amp;gt;&lt;br /&gt;
{{PRJCOMandatory20252026}}&lt;br /&gt;
{{TOCright}}&lt;br /&gt;
== Método de Avaliação do Projecto ==&lt;br /&gt;
&lt;br /&gt;
A avaliação relativa à componente do Projecto processa-se em várias fases:&lt;br /&gt;
&lt;br /&gt;
* [[#Entrega Zero (inicial) - Projecto Base|Entrega Zero (inicial): projecto base]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Entrega Intermédia - Gerador de XML|Entrega Intermédia: gerador de XML]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Entrega Final - Compilador Completo|Entrega Final: compilador completo]] (&#039;&#039;&#039;obrigatória&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
* [[#Teste Prático|Teste prático]] (&#039;&#039;&#039;obrigatório&#039;&#039;&#039;: ver condições abaixo)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--O Projecto (trabalho conducente às entregas acima mencionadas e abaixo descritas) é realizado individualmente, durante o período estabelecido.--&amp;gt;&lt;br /&gt;
O Projecto (trabalho conducente às entregas acima mencionadas e abaixo descritas) é realizado por grupos de, no máximo, 2 (dois) elementos, durante o período estabelecido.&lt;br /&gt;
&lt;br /&gt;
O Teste Prático é realizado individualmente, em data e local a agendar.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A não realização de componentes obrigatórias tem como consequência a classificação de zero valores na componente de projecto e exclusão da avaliação em época normal.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&#039;&#039;&#039;TODAS AS ENTREGAS SÃO REALIZADAS ATÉ ÀS 12:00 (&amp;quot;meio-dia&amp;quot;) DAS RESPECTIVAS DATAS&#039;&#039;&#039;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;TODAS AS ENTREGAS SÃO OBRIGATÓRIAS E SÃO REALIZADAS ATÉ ÀS 17:00 DAS RESPECTIVAS DATAS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Cálculo da Nota do Projecto e Condições de Aprovação ==&lt;br /&gt;
&lt;br /&gt;
Componentes de avaliação:&lt;br /&gt;
* &#039;&#039;&#039;PRJ&#039;&#039;&#039; - nota final do projecto&lt;br /&gt;
* &#039;&#039;&#039;E0&#039;&#039;&#039; - nota da entrega &amp;quot;zero&amp;quot;&lt;br /&gt;
* &#039;&#039;&#039;EI&#039;&#039;&#039; - nota da entrega intermédia&lt;br /&gt;
* &#039;&#039;&#039;EF&#039;&#039;&#039; - nota da entrega final&lt;br /&gt;
* &#039;&#039;&#039;TP&#039;&#039;&#039; - nota do teste prático&lt;br /&gt;
&lt;br /&gt;
A nota do teste prático condiciona a distância ao mínimo entre as notas do teste prático e a do projecto: desde um mínimo de 12.5% de acréscimo à menor das duas (abaixo de 7.5 valores no TP), até um máximo de 25% (para 20 valores no TP). O acréscimo é linear entre 7.5 e 20. &lt;br /&gt;
&lt;br /&gt;
Ou seja:&lt;br /&gt;
* &#039;&#039;&#039;PRJ = min(E0+EI+EF, TP) + | TP - E0 - EI - EF | * max(12.5, TP+5) / 100&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Condições necessárias para aprovação à disciplina (necessárias todas):&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;PRJ &amp;gt;= 9.5&#039;&#039;&#039; (sem arredondamento)&lt;br /&gt;
* &#039;&#039;&#039;PRJ != NA&#039;&#039;&#039; &lt;br /&gt;
* &#039;&#039;&#039;TP &amp;gt; 0&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;TP != NA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Zero (inicial) - Projecto Base ==&lt;br /&gt;
&lt;br /&gt;
A Entrega &amp;quot;Zero&amp;quot; avalia o estado do projecto relativamente à concepção dos nós que representam os conceitos da linguagem (sem ser necessário tratar ainda do seu reconhecimento ou processamento).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 2 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Não serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Nesta fase, além da estrutura básica do compilador, todas as classes dos nós da linguagem, assim como os esqueletos dos &amp;quot;visitors&amp;quot; (xml_writer, postfix_writer, etc.) devem estar implementados. Não é ainda necessário ter implementado nenhum código de análise lexical, sintáctica ou semântica.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega &amp;quot;zero&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Considerando que é um passo crucial na concepção do projecto, a não realização desta entrega conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente exclusão da avaliação da disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Intermédia - Gerador de XML ==&lt;br /&gt;
&lt;br /&gt;
A Entrega Intermédia avalia o estado do projecto relativamente a um mínimo de funcionalidade.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 6 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Não serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Ver pormenores na [[Compiladores#Pautas|pauta da avaliação da entrega intermédia]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização da Entrega Intermédia conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Entrega Final - Compilador Completo ==&lt;br /&gt;
&lt;br /&gt;
A Entrega Final pressupõe que todo o projecto foi implementado.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Esta entrega é obrigatória e tem uma classificação máxima de 12 valores.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Serão executados testes automáticos nesta entrega.&lt;br /&gt;
&lt;br /&gt;
Os testes correspondem a uma série de programas que deverão ser compilados pelo resultado do projecto de cada grupo e cuja execução deve corresponder a um conjunto de resultados padrão.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização da Entrega Final conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente. A ausência de material relevante para a entrega será considerada uma não entrega, conduzindo a reprovação.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Teste Prático ==&lt;br /&gt;
&lt;br /&gt;
O Teste Prático consiste em fazer pequenas alterações/extensões ao projecto descrito no enunciado. O teste é realizado com base na implementação submetida para a avaliação correspondente à entrega final.&lt;br /&gt;
&lt;br /&gt;
Este teste avalia o conhecimento do aluno relativamente ao projecto entregue, assim como a sua capacidade de realizar alterações ao código do projecto.&lt;br /&gt;
&lt;br /&gt;
O teste prático é como uma discussão de projecto, pelo que não existem repescagens como nos testes escritos. Alunos que faltem ao teste prático estão automaticamente reprovados à disciplina.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;A não realização do Teste Prático conduz automaticamente a uma classificação de 0 (zero) na componente de avaliação relativa ao Projecto e consequente reprovação à disciplina no ano lectivo corrente.&amp;lt;/font&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Concretamente, o teste prático corresponde à resolução uma pergunta que aborda os seguintes três tópicos:&lt;br /&gt;
análise lexical;&lt;br /&gt;
análise sintáctica; e&lt;br /&gt;
análise semântica e geração de código.&lt;br /&gt;
Cada tópico pode ser resolvido com mais ou menos profundidade (embora isso implique funcionamento possivelmente deficiente a jusante) e será avaliado independentemente.&lt;br /&gt;
&lt;br /&gt;
== Considerações Adicionais sobre a Avaliação do Projecto ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;O projecto deverá ser desenvolvido atempadamente ao longo do semestre.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
As versões intermédias registadas no Gitlab poderão ser testadas, pelo que deverão ser periodicamente actualizadas. O projecto é constituído por um projecto Gitlab designado pelo número do grupo que o executa. O repositório GIT disponibilizado já contém uma versão vazia do projecto. Apenas os ficheiros registados no projecto Gitlab serão considerados na avaliação.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Não serão consideradas quaisquer alterações aos ficheiros disponibilizados: eventuais cópias desses ficheiros serão automaticamente substituídas durante a avaliação da funcionalidade do código submetido.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A avaliação executa testes automáticos aos programas na linguagem a implementar: caso os testes falhem por causas imputáveis ao grupo, a nota reflectirá apenas os testes bem sucedidos. Para tal, o compilador deve chamar-se &#039;&#039;&#039;p6&#039;&#039;&#039; e não &amp;quot;P6&amp;quot;, &amp;quot;proj&amp;quot;, &amp;quot;compiladores&amp;quot;, &amp;quot;projecto&amp;quot;, ou outro nome (a makefile fornecida já faz este trabalho). As restantes componentes da nota são obtidas pela análise do código e resultado do teste prático (realizado individualmente). O código é avaliado quanto à sua correcção, simplicidade, extensibilidade e legibilidade: devem existir comentários das partes mais complexas, mas não devem ser excessivos nem óbvios (diminuem a legibilidade), nem muito escassos (impedem a compreensão). O teste prático avalia a capacidade de efectuar alterações ao código entregue.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Qualquer alteração à especificação da linguagem é penalizada, mesmo que possa ser entendida como um melhoramento.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Notar que o facto de os testes automáticos terem sido superados não reflecte a qualidade do código, quer do ponto de vista de engenharia de software, quer do ponto de vista da correcta aplicação dos princípios leccionados na disciplina. No entanto, a funcionalidade do compilador final também é importante, pelo que &#039;&#039;&#039;é preferível um compilador que realize, correctamente, apenas parte da funcionalidade a um quase completo mas que nem sequer compila ou que não gera nenhum programa correcto&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Compromisso de Honra ==&lt;br /&gt;
&lt;br /&gt;
A entrega de quaisquer trabalhos pressupõe o compromisso de honra que foram realizados pelos autores referenciados. A quebra deste compromisso, i.e., a tentativa de apropriação de trabalhos alheios, terá como consequência a reprovação de todos os alunos envolvidos (incluindo os que possibilitaram a ocorrência) no ano lectivo actual, sem prejuízo de acções disciplinares previstas pelo IST.&lt;br /&gt;
&lt;br /&gt;
[[category:Projecto de Compiladores]]&lt;br /&gt;
[[category:Compiladores]]&lt;br /&gt;
[[category:Ensino]]&lt;/div&gt;</summary>
		<author><name>Root</name></author>
	</entry>
</feed>