TUTOR - TUTOR

TUTOR
Paradigma imperativo ( procedimental )
Projetado por Paul Tenczar e Richard Blomme
Desenvolvedor Paul Tenczar e Universidade de Illinois em Urbana-Champaign
Apareceu pela primeira vez 1969 ( 1969 )
Disciplina de digitação Nenhum
Implementações principais
TUTOR, Micro-TUTOR
Influenciado
TenCORE , USE ( Sistemas de Regência )

TUTOR , também conhecido como PLATO Author Language , é uma linguagem de programação desenvolvida para uso no sistema PLATO na Universidade de Illinois em Urbana-Champaign começando por volta de 1965. TUTOR foi inicialmente projetado por Paul Tenczar para uso em instrução assistida por computador (CAI) e instrução gerenciada por computador (CMI) (em programas de computador chamados "aulas") e tem muitos recursos para esse fim. Por exemplo, o TUTOR possui poderosos comandos, gráficos e recursos de análise e julgamento de respostas para simplificar o manuseio dos registros e estatísticas dos alunos pelos instrutores. A flexibilidade do TUTOR, em combinação com o poder computacional do PLATO (rodando no que foi considerado um supercomputador em 1972), também o tornou adequado para a criação de jogos - incluindo simuladores de vôo, jogos de guerra, RPG multiplayer estilo masmorra, jogos de cartas, palavras jogos e jogos de aula de medicina, como Bugs and Drugs ( BND ). TUTOR vive hoje como a linguagem de programação para o sistema Cyber1 PLATO, que executa a maior parte do código-fonte PLATO dos anos 1980 e tinha cerca de 5.000 usuários em junho de 2020.

Origens e desenvolvimento

TUTOR foi originalmente desenvolvido como uma linguagem de autoria de propósito especial para projetar aulas de instrução, e sua evolução para uma linguagem de programação de propósito geral não foi planejada. O nome TUTOR foi aplicado pela primeira vez à linguagem de autoria do sistema PLATO nos últimos dias de Platão III. A primeira documentação do idioma, com este nome, parece ter sido The TUTOR Manual , CERL Report X-4, de RA Avner e P. Tenczar, janeiro de 1969.

O artigo Ensinando a tradução de russo por computador oferece um instantâneo do TUTOR pouco antes de o PLATO IV entrar em operação. Os elementos centrais da linguagem estavam presentes, mas os comandos eram dados em maiúsculas e, em vez de usar um mecanismo geral, o suporte para conjuntos de caracteres alternativos era por meio de nomes de comandos especiais, como WRUSS"escrever usando o conjunto de caracteres russo".

Ao longo da década de 1970, os desenvolvedores do TUTOR aproveitaram o fato de todo o corpus de programas do TUTOR estar armazenado on-line no mesmo sistema de computador. Sempre que sentiram a necessidade de alterar o idioma, eles executaram o software de conversão sobre o corpus do código TUTOR para revisar todo o código existente para que ficasse em conformidade com as alterações feitas. Como resultado, uma vez que novas versões do TUTOR foram desenvolvidas, manter a compatibilidade com a versão PLATO pode ser muito difícil.

A Control Data Corporation (CDC), em 1981, eliminou amplamente o nome TUTOR de sua documentação PLATO. Eles se referiram à própria linguagem como a linguagem do autor PLATO . A frase arquivo TUTOR ou mesmo arquivo de lição TUTOR sobreviveu, entretanto, como o nome do tipo de arquivo usado para armazenar texto escrito na linguagem do autor PLATO.

Estrutura de uma aula TUTOR

Uma aula de TUTOR consiste em uma sequência de unidades onde cada unidade começa com a apresentação de informações e o progresso de uma unidade para a próxima depende de responder corretamente uma ou mais questões. Tal como acontece com os parágrafos COBOL , o controle pode entrar em uma unidade TUTOR da unidade anterior e sair para a próxima, mas as unidades também podem ser chamadas como sub-rotinas usando os comandos doou join.

Aqui está um exemplo de unidade da página 5 do TUTOR User Memo , março de 1973 ( Computer-based Education Research Laboratory , University of Illinois at Urbana-Champaign):

unit    math
at      205
write   Answer these problems

        3 + 3 =

        4 × 3 =

arrow   413
answer  6
arrow   613
answer  12

Várias coisas devem ficar imediatamente aparentes neste exemplo.

  • Primeiro, TUTOR é uma linguagem de formato fixo. Cada linha começa com um nome de comando, que deve caber em um campo fixo de 8 caracteres para o nome do comando. Os argumentos para esse comando (a tag ) começam no 9º caractere. Embora uma tecla tab tenha sido usada para chegar à 9ª coluna, ela gerou espaços, pois plato não tinha caractere de tabulação.
  • Em alguns casos, como o writecomando acima, a tag pode consistir em várias linhas. As linhas de continuação estão em branco ou têm uma guia inicial.
  • As coordenadas da tela são apresentadas como números únicos, portanto, 205 se refere à linha 2, coluna 5, e 413, à linha 4, coluna 13.

O que pode não estar aparente é a estrutura de controle implícita nesta unidade. O arrowcomando marca a entrada para um bloco de julgamento. Esta estrutura de controle é uma das características únicas do TUTOR.

Características únicas

TUTOR continha vários recursos exclusivos. A lista a seguir não pretende substituir um manual do TUTOR, mas apenas destaca os recursos mais interessantes, inovadores e às vezes confusos da linguagem.

Julgamento de resposta

Um bloco de julgamento em TUTOR é uma estrutura de controle que começa com um arrowcomando e termina com o próximo arrow, endarrowou unitcomando. O arrowcomando também solicita entrada, com o caractere de seta especial (semelhante a "▷") exibido como um prompt nas coordenadas de tela indicadas. Na verdade, um bloco de julgamento pode ser pensado como uma estrutura de controle de retrocesso, onde o aluno pode fazer várias tentativas de responder a uma pergunta até que uma resposta correta permita o progresso.

Julgamento de correspondência de padrões

Cada bloco de julgamento consiste em uma sequência de comandos de correspondência de padrões , cada um dos quais introduz um bloco (possivelmente vazio) de comandos a serem executados se esse padrão corresponder. Os dois comandos de correspondência de padrões mais comuns eram answere wrong. Eles tinham uma semântica de correspondência de padrões idêntica, exceto que answerjulgou a resposta do aluno como correta se correspondesse, enquanto wrongjulgou a resposta do aluno como incorreta.

Os campos de tag nos comandos answere wrongconsistiam em listas de palavras opcionais, obrigatórias e alternativas. considere este exemplo do exercício 4-1 no Memo do usuário do TUTOR de 1973 :

answer  <it, is,a, it's, figure,
        polygon>
        (right, rt) (triangle, triangular)

Isso corresponderia a respostas como "é um triângulo retângulo" ou "é uma figura triangular" ou apenas "triângulo rt". Não corresponderia a "tipo de triangular" porque as palavras "tipo de" não são listadas como ignoradas e não corresponderia a "triângulo, certo?" porque a ordem está errada.

O subsistema de correspondência de padrões reconheceu erros de ortografia, portanto, as palavras "triangel" ou "triangl" corresponderiam ao padrão de exemplo. O autor da lição poderia usar o specscomando para definir o quão pedante era o sistema em relação aos erros ortográficos.

Os algoritmos de correspondência de padrões usados ​​por várias implementações de TUTOR variavam em detalhes, mas, normalmente, cada palavra no texto de entrada e cada palavra no padrão eram convertidas em vetores de bits . Para ver se uma palavra da entrada do aluno correspondia a uma palavra do padrão, a distância de Hamming entre os dois vetores de bits foi usada como uma medida do grau de diferença entre as palavras. Os vetores de bits tinham tipicamente 60 ou 64 bits de comprimento, com campos para presença de letras, presença de pares de letras e a primeira letra. Como resultado, o número de bits de um no exclusivo ou de dois desses vetores de bits aproximava-se da extensão da diferença fonética entre as palavras correspondentes.

Julgando estruturas de controle

Todas as primeiras apresentações da estrutura de controle de um bloco de julgamento do TUTOR eram confusas. Em termos modernos, entretanto, um bloco de julgamento pode ser descrito como uma estrutura de controle iterativa que sai quando a entrada do aluno é considerada correta. O corpo dessa estrutura de controle consiste em uma série de casos , cada um introduzido por um comando de correspondência de padrões , como answerou wrong. Todas as saídas produzidas pelo corpo do loop de julgamento no ciclo anterior são apagadas da tela antes do próximo ciclo.

Considere este exemplo, do exercício 4-1 do Memo do usuário do TUTOR de 1973 :

wrong   <it, is,a> square
at      1501
write   A square has four
        sides.

No caso de o aluno inserir "quadrado" ou "quadrado", a resposta será considerada incorreta e o texto "Um quadrado tem quatro lados". é a saída começando na linha 15, coluna 1 na tela. Essa saída permanece na tela até que o aluno comece a inserir uma nova resposta, momento em que é apagada para que a resposta à nova resposta possa ser computada. O mecanismo pelo qual a tela retorna ao seu estado anterior varia de implementação para implementação. As primeiras implementações operaram colocando o terminal no modo de apagamento e reexecutando todo o caso correspondente. Algumas implementações posteriores armazenaram em buffer a saída produzida durante o julgamento para que essa saída pudesse ser apagada.

O joincomando era uma forma única de chamada de subrotina. Foi definido como sendo equivalente à substituição textual do corpo da unidade combinada no lugar do próprio comando de junção (página 21, 1973 TUTOR User Memo ). Como tal, uma unidade unida pode conter parte de um bloco de julgamento. Assim, embora o bloco de julgamento seja conceitualmente um iterador envolvendo uma série de casos , esse bloco pode ser dividido arbitrariamente em sub-rotinas. (Uma chamada de sub-rotina alternativa, o docomando, está em conformidade com a semântica usual associada a chamadas de sub-rotina em outras linguagens de programação.)

Comandos gráficos e de exibição

O terminal de aluno PLATO IV tinha um painel de tela de plasma de 512 por 512 pixels , com suporte de hardware para plotagem de pontos , desenho de linha e exibição de texto. Cada pixel no terminal PLATO IV era laranja ou preto. O terminal CDC PLATO V usou um CRT preto e branco monocromático para emular o painel de plasma. O conjunto de caracteres embutido tinha 4 conjuntos de 63 caracteres, cada um com 8 por 16 pixels, metade deles eram fixos, a outra metade eram programáveis. O idioma do Tutor forneceu suporte completo para este terminal.

Havia dois sistemas de coordenadas (consulte a página II-1 de The TUTOR Language de Bruce Sherwood):

  • Coordenadas grosseiras foram especificadas em termos de linhas e colunas de texto. A coordenada grosseira 1501, por exemplo, era uma referência ao caractere 1 da linha 15, onde o caractere superior esquerdo na tela estava no local 101 e o caractere inferior direito estava em 3264.
  • Coordenadas finas foram especificadas como coordenadas X e Y em relação ao canto esquerdo inferior da tela. A coordenada fina 0,511 especificava o canto esquerdo superior da tela, enquanto 0,496 era equivalente ao 101, permitindo a altura de 16 pixels de um personagem e o fato de que os personagens eram plotados em relação ao seu canto esquerdo inferior.

Comandos de desenho

O exemplo a seguir ilustra alguns dos comandos de desenho do Mestre.

draw    1812;1852;skip;1844;1544
circle  16,344,288
draw    1837;1537;1535;1633;1833

Observe o uso de ponto-e-vírgula para separar coordenadas sucessivas no drawcomando. Isso permite o uso inequívoco de coordenadas finas separadas por vírgula. Normalmente, o comando desenhar conecta pontos consecutivos com segmentos de linha, mas ao colocar skipa etiqueta, o drawcomando poderia ser feito para levantar conceitualmente sua caneta.

As marcas no circlecomando fornecem o raio e as coordenadas finas do centro. Tags adicionais podem especificar ângulos iniciais e finais para círculos parciais.

Comandos de desenho de composição à mão são difíceis, então um editor de imagens foi incluído no sistema PLATO em 1974 para automatizar este trabalho. Isso só poderia lidar com comandos de desenho com coordenadas constantes.

Comandos de renderização de texto

O exemplo a seguir ilustra algumas das ferramentas de renderização de texto do Tutor.

unit    title
size    9.5     $$ text 9.5 times normal size
rotate  45      $$ text rotated 45 degrees
at      2519
write   Latin
size    0       $$ return to normal writing
rotate  0
at      3125
write   Lessons on Verbs

Texto renderizado em tamanho zero rotação zero usava o hardware de renderização de caractere embutido do terminal PLATO, enquanto a renderização com tamanho diferente de zero e rotação era feita com segmentos de linha e, portanto, significativamente mais lento devido à velocidade do link de comunicação com o terminal.

Estruturas de controle

Além de seus mecanismos de julgamento de resposta exclusivos, o conjunto original de estruturas de controle do TUTOR era bastante esparso. Em meados de 1970, esta lacuna foi abordada através da introdução if, endifblocos com opcional elseife elseseções. A semântica dessas estruturas de controle era rotineira, mas a sintaxe herdou o recuo obrigatório da Tutor Language, pressagiando o do Python e adicionando um caractere de recuo não vazio exclusivo para distinguir o recuo das linhas de continuação.

Isso é ilustrado no exemplo a seguir, da página S5 do Resumo de Comandos e Variáveis ​​de Sistema do TUTOR (10ª ed) por Elaine Avner , 1981:

if      n8<4
.       write   first branch
.       calc    n9⇐34
elseif  n8=4
.       write   second branch
.       do      someunit
else
.       write   default branch
.       if      n8>6
.       .       write   special branch
.       endif
endif

(A seta de atribuição na calcinstrução não é renderizada corretamente em alguns navegadores. Parece semelhante a <=, mas como um caractere. Tinha uma tecla dedicada no teclado PLATO IV.)

A mesma sintaxe foi usada para loop, endloopblocos com semântica comparável à enquanto lacetes em linguagens de programação convencionais. Isso é ilustrado no exemplo a seguir, da página S6 do Resumo de Comandos e Variáveis ​​de Sistema do TUTOR (10ª ed) por Elaine Avner, 1981:

loop    n8<10
.       write   within loop
.       sub1    n8
reloop  n8≥5
.       write   still within loop
.       do      someunit
outloop n8<3
.       write   still within loop
endloop
write   outside of loop

Observe que os comandos reloope outloopsão um tanto análogos aos comandos continuee breakdas linguagens baseadas em C , exceto que eles devem ficar no nível de recuo do loop que modificam e têm uma etiqueta de condição que indica quando a transferência de controle indicada deve ocorrer . Isso torna a construção mais poderosa do que em outras linguagens, porque qualquer linha do loop interno pode terminar ou reinicializar vários loops externos com uma instrução.

Expressão sintática

A sintaxe da expressão de TUTOR não remontava à sintaxe do FORTRAN , nem era limitada por conjuntos de caracteres mal projetados da época. Por exemplo, o conjunto de caracteres PLATO IV incluía caracteres de controle para subscrito e sobrescrito , e TUTOR os usava para exponenciação. Considere este comando (da página IV-1 de The TUTOR Language , Sherwood, 1974):

circle  (412+72.62)1/2,100,200

O conjunto de caracteres também incluía os símbolos convencionais de multiplicação e divisão ×e ÷, mas em um afastamento mais radical das convenções estabelecidas pelo FORTRAN, permitia a multiplicação implícita, de modo que as expressões (4+7)(3+6)e eram válidas, com os valores 99 e 15,9, respectivamente (op cit). Esse recurso foi visto como essencial. Quando os alunos digitavam uma resposta numérica a uma pergunta, eles podiam usar operadores e variáveis ​​e notação algébrica padrão, e o programa usaria o comando TUTOR "computar" para compilar e executar a fórmula e verificar se era numericamente equivalente (ou dentro do erro de arredondamento de ponto flutuante) para a resposta correta. 3.4+5(23-3)/2

A linguagem incluía uma constante pré-definida nomeada com a letra grega pi (π), com o valor apropriado, que poderia ser usada em cálculos. Assim, a expressão poderia ser usada para calcular a área de um círculo, usando a constante π embutida, a multiplicação implícita e a exponenciação indicadas por um sobrescrito. πr2

No TUTOR, a comparação de ponto flutuante x=yfoi definida como sendo verdadeira se xe yfosse aproximadamente igual (consulte a página C5 do PLATO User Memo, Number One de Avner, 1975). Essa vida simplificada para desenvolvedores matematicamente ingênuos de lições instrucionais, mas ocasionalmente causou dor de cabeça para desenvolvedores de código numericamente sofisticado porque era possível que ambos x<ye x≥ypudessem ser verdadeiros ao mesmo tempo.

Gerenciamento de memória

Como uma linguagem de autoria, TUTOR começou com apenas recursos mínimos de memória e apenas as ferramentas mais rudes para manipulá-los. Cada processo do usuário tinha um segmento de dados privados de 150 variáveis, e blocos comuns compartilhados podiam ser anexados, permitindo a comunicação entre os usuários por meio de memória compartilhada.

No sistema PLATO IV, as palavras tinham 60 bits, de acordo com a família de computadores CDC 6600 . Algumas implementações posteriores mudaram isso para 64 bits.

Recursos básicos de memória

A região de memória privada de cada processo consistia em 150 palavras cada, denominadas variáveis ​​de aluno; os valores dessas variáveis ​​eram persistentes, acompanhando o usuário individual de sessão para sessão. Eles foram endereçados como n1through n150quando usados ​​para conter valores inteiros, ou como v1through v150quando usados ​​para manter valores de ponto flutuante.

Uma lição TUTOR pode anexar uma única região de até 1500 palavras de memória compartilhada usando o commoncomando. Cada lição pode ter um bloco comum temporário sem nome contendo variáveis ​​compartilhadas por todos os usuários daquela lição. Esses bloqueios foram criados quando uma lição começou a ser usada e desalocados quando a lição se tornou inativa. Em contraste, blocos comuns nomeados foram associados a um bloco de uma lição (um arquivo de disco). A memória compartilhada foi endereçada como nc1through nc1500(para inteiros) ou vc1through vc1500(para números de ponto flutuante).

Onde 150 variáveis ​​de aluno eram insuficientes, uma aula poderia usar o storagecomando para criar um segmento de memória privada adicional de até 1000 palavras. Este segmento existia apenas no espaço de troca, mas poderia ser mapeado para variáveis ​​de aluno ou variáveis ​​comuns. Por exemplo (da página X-11 de The TUTOR Language , Sherwood, 1974):

common  1000
storage 75
stoload vc1001,1,75

Este exemplo define nc1a nc1000como um compartilhada bloco comum sem nome, enquanto nc1001que nc1075são armazenagem privada.

Definição de nomes simbólicos

O definecomando Tutor era muito semelhante à diretiva do pré-processador C. Essa era a única maneira de associar nomes mnemônicos a variáveis. Cabia ao programador alocar estaticamente a memória e atribuir nomes às variáveis. Considere este exemplo da página 17 do TUTOR User Memo - Introduction to TUTOR , 1973 " #define

define  mynames
        first=v1, second =v2
        result=v3

Isso cria um conjunto de definições denominado mynamesdefinição de três variáveis ​​de ponto flutuante. Os usuários foram avisados ​​de que " não deve haver nenhum v3 ou v26 em qualquer lugar da sua lição, exceto na defineprópria instrução . Coloque todas as suas definições no início da lição, onde você terá uma referência pronta para as variáveis ​​que está usando." (sublinhado do original, página IV-5 de The TUTOR Language , Sherwood, 1974.)

As funções podem ser definidas, com semântica de substituição de macro, como nesta ilustração da página IX-2 de The TUTOR Language , Sherwood, 1974:

define  cotan(a)=cos(a)/sin(a)

Ao contrário de C, as regras de escopo originais do TUTOR eram pura "definição antes do uso", sem provisões para definições locais. Assim, o parâmetro formal autilizado acima não deve ter nenhuma definição prévia.

Mais tarde, no desenvolvimento do TUTOR, com a introdução de vários conjuntos nomeados de definições, o programador recebeu controle explícito sobre quais conjuntos de definições estavam em vigor. Por exemplo, define purge, setnamedescartaria todas as definições no conjunto nomeado.

Matrizes, matrizes compactadas e manipulação de texto

As ferramentas originais do TUTOR para manipulação de texto baseavam-se em comandos para operações de texto específicas, por exemplo, packcolocar uma sequência de caracteres compactada em variáveis ​​consecutivas na memória, searchpesquisar uma sequência dentro de outra e movemover uma sequência de memória para memória. Em 1975, ferramentas mais gerais para matrizes de inteiros e matrizes compactadas foram adicionadas. A página 14 do Memorando do Usuário PLATO - Resumo dos Comandos do TUTOR e Variáveis ​​do Sistema , Avner, 1975, fornece o seguinte:

define  segment, name=starting var, num bits per byte, s
        array, name(size)=starting var
        array, name (num rows, num columns)=starting var

Matrizes segmentadas , definidas com a palavra-chave segment, eram comparáveis ​​a matrizes compactadas em Pascal . O tamanho do byte e se os elementos da matriz deveriam ou não ser tratados como assinados ou não assinados estavam inteiramente sob o controle do usuário. Manipulação texto arbitrária pode ser feito ajustando o tamanho de byte para o tamanho da máquina de byte, 6 bits de implementações utilizando código de exibição , 8 bits em alguns mais tarde ASCII e ASCII estendidos implementações. Observe a falta de qualquer especificação de dimensionalidade de array para arrays segmentados.

Passagem de parâmetro

Um mecanismo geral de passagem de parâmetros foi adicionado ao TUTOR no início da era PLATO IV. A página IV-10 de The TUTOR Language de Sherwood, 1974 dá o seguinte exemplo:

define  radius=v1,x=v2,y=v3
unit    vary
do      halfcirc(100,150,300)
do      halfcirc(50)
*
unit    halfcirc(radius, x,y)
circle  radius, x,y,0,180
draw    x-radius, y;x+radius, y

Observe que os parâmetros formais listados na lista de argumentos do unitcomando são simplesmente os nomes definidos para variáveis ​​globais alocadas estaticamente. A semântica de passagem de parâmetros foi dada como sendo equivalente à atribuição no momento da transferência do controle para a unidade de destino, e se os parâmetros reais fossem omitidos, como no segundo docomando acima, o efeito era deixar os valores anteriores do formal correspondente parâmetros inalterados.

Variáveis ​​locais

Variáveis ​​locais foram adicionadas ao TUTOR por volta de 1980. Os autores das aulas que desejassem usar variáveis ​​locais foram obrigados a usar o lvarscomando para declarar o tamanho do buffer usado para variáveis ​​locais, até 128 palavras. Feito isso, uma unidade usando variáveis ​​locais poderia começar da seguinte maneira (da página C2 do Resumo de Comandos e Variáveis ​​de Sistema do TUTOR , Avner, 1981):

unit    someu
        NAME1,NAME2,NAME3(SIZE)
        NAME4=CONSTANT
        floating:NAME5,NAME6,NAME7(SIZE)
        integer, NUM BITS:NAME8,NAME9
        integer, NUM BITS,signed:NAME10
        integer:NAME11

As linhas de continuação do unitcomando fornecido acima são consideradas linhas de um definecomando implícito com escopo local . Definições convencionais em termos de variáveis ​​de aluno, como as que n150poderiam ser usadas em tal local define, mas todas as formas ilustradas aqui vinculam nomes automaticamente a locais no bloco de memória alocado pelo lvarscomando. A documentação TUTOR disponível não discute como as variáveis ​​locais são alocadas.

Outras implementações

Existe uma família considerável de idiomas relacionados ao TUTOR, cada um semelhante ao idioma original do TUTOR, mas com diferenças. Em particular, o TUTOR era um componente de um sistema (o sistema de educação baseado em computador PLATO) executado em um hardware de mainframe CDC específico. Para eficiência, havia alguns elementos específicos de hardware no TUTOR (por exemplo, variáveis ​​que eram palavras de 60 bits que podiam ser usadas como matrizes de 60 bits ou como 10 caracteres de seis bits, etc.). Além disso, o TUTOR foi projetado antes do advento da interface gráfica do usuário (GUI) orientada para o Windows.

A linguagem microTutor foi desenvolvida no projeto PLATO na UIUC para permitir que partes de uma aula rodassem em terminais que continham microcomputadores, com conexões para o código TUTOR rodando no mainframe. O dialeto microTutor também foi a linguagem de programação do sistema Cluster desenvolvido na UIUC e licenciado para a TDK no Japão; o sistema de cluster consistia em um pequeno grupo de terminais conectados a um minicomputador que fornecia armazenamento e compilação. O Tencore Language Authoring System é um derivado do TUTOR desenvolvido por Paul Tenczar para PCs e vendido pela Computer Teaching Corporation. cT era um derivado de TUTOR e microTutor desenvolvido na Carnegie Mellon que permitia que programas rodassem sem mudanças em ambientes GUI em janelas em sistemas Windows, Mac e Unix / Linux: The cT Programming Language Archives

Referências

links externos