Oberon-2 - Oberon-2
Paradigmas | Imperativo , estruturado , modular , orientado a objetos |
---|---|
Família | Wirth Oberon |
Projetado por |
Niklaus Wirth Hanspeter Mössenböck |
Desenvolvedor | ETH Zurique |
Apareceu pela primeira vez | 1991 |
Disciplina de digitação | Forte , híbrido ( estático e dinâmico ) |
Alcance | Lexical |
Plataforma | Ceres ( NS32032 ), IA-32 , x86-64 |
SO | Windows , Linux , Solaris , macOS |
Local na rede Internet | www |
Influenciado por | |
Oberon , Modula-2 , Object Oberon | |
Influenciado | |
Oberon-07 , Zonnon , Active Oberon , Component Pascal , Go , Nim |
Oberon-2 é uma extensão da linguagem de programação Oberon original que adiciona reflexão limitada e recursos de programação orientada a objetos , arrays abertos como tipos de base de ponteiro, exportação de campo somente leitura e reintroduz o loop do Modula-2 .
FOR
Foi desenvolvido em 1991 na ETH Zurich por Niklaus Wirth e Hanspeter Mössenböck , que agora está no Institut für Systemsoftware (SSW) da Universidade de Linz , Áustria. Oberon-2 é um superconjunto de Oberon, é totalmente compatível com ele e foi um redesenho do Object Oberon .
Oberon-2 herdou reflexão limitada e herança única ("extensão de tipo") sem as interfaces ou mixins de Oberon, mas adicionou métodos virtuais eficientes ("procedimentos de tipo vinculado"). As chamadas de método foram resolvidas em tempo de execução usando tabelas de método virtual no estilo C ++ .
Em comparação com linguagens totalmente orientadas a objetos como Smalltalk , em Oberon-2, classes e tipos de dados básicos não são objetos , muitas operações não são métodos, não há passagem de mensagem (pode ser emulado um pouco por reflexão e por extensão de mensagem, como demonstrado em ETH Oberon), e o polimorfismo é limitado a subclasses de uma classe comum (sem digitação de pato como em Python e não é possível definir interfaces como em Java ). Oberon-2 não suporta encapsulamento em nível de objeto ou classe, mas módulos podem ser usados para este propósito.
O Reflection em Oberon-2 não usa metaobjetos , mas simplesmente lê descritores de tipo compilados nos binários executáveis e expostos nos módulos que definem os tipos e / ou procedimentos. Se o formato dessas estruturas for exposto no nível da linguagem (como é o caso de ETH Oberon, por exemplo), a reflexão poderia ser implementada no nível da biblioteca . Assim, ele poderia ser implementado quase inteiramente no nível da biblioteca, sem alterar o código da linguagem. De fato, ETH Oberon faz uso extensivo de habilidades de reflexão em nível de linguagem e em nível de biblioteca.
Oberon-2 fornece suporte de tempo de execução integrado para coleta de lixo semelhante a Java e executa verificações de limites e índices de array, etc., que eliminam os problemas potenciais de substituição de limites de pilha e array e problemas de gerenciamento de memória manual inerentes em C e C ++. A compilação separada usando arquivos de símbolo e namespaces por meio da arquitetura do módulo garante reconstruções rápidas, uma vez que apenas os módulos com interfaces alteradas precisam ser recompilados.
O componente de linguagem Pascal é um refinamento (um superconjunto) de Oberon-2.
Código de exemplo
O seguinte código Oberon-2 implementa uma árvore binária simples:
MODULE Trees;
TYPE
Tree* = POINTER TO Node;
Node* = RECORD
name-: POINTER TO ARRAY OF CHAR;
left, right: Tree
END;
PROCEDURE (t: Tree) Insert* (name: ARRAY OF CHAR);
VAR p, father: Tree;
BEGIN p := t;
REPEAT father := p;
IF name = p.name^ THEN RETURN END;
IF name < p.name^ THEN p := p.left ELSE p := p.right END
UNTIL p = NIL;
NEW(p); p.left := NIL; p.right := NIL; NEW(p.name, LEN(name)+1); COPY(name, p.name^);
IF name < father.name^ THEN father.left := p ELSE father.right := p END
END Insert;
PROCEDURE (t: Tree) Search* (name: ARRAY OF CHAR): Tree;
VAR p: Tree;
BEGIN p := t;
WHILE (p # NIL) & (name # p.name^) DO
IF name < p.name^ THEN p := p.left ELSE p := p.right END
END;
RETURN p
END Search;
PROCEDURE NewTree* (): Tree;
VAR t: Tree;
BEGIN NEW(t); NEW(t.name, 1); t.name[0] := 0X; t.left := NIL; t.right := NIL; RETURN t
END NewTree;
END Trees.
Oberon-2 extensões para Oberon
Procedimentos ligados ao tipo
Os procedimentos podem ser vinculados a um tipo de registro (ou ponteiro). Eles são equivalentes aos métodos de instância na terminologia orientada a objetos.
Exportação somente leitura
O uso de variáveis exportadas e campos de registro pode ser restrito ao acesso somente leitura. Isso é mostrado com um sinalizador de visibilidade "-".
Arrays abertos
Arrays abertos que antes só podiam ser declarados como tipos de parâmetros formais agora podem ser declarados como tipos de base de ponteiro.
Declaração FOR
A FOR
declaração de Pascal e Modula-2 não foi implementada em Oberon. É reintroduzido em Oberon-2.
Verificação de tipo de tempo de execução
Oberon-2 fornece vários mecanismos para verificar o tipo dinâmico de um objeto. Por exemplo, onde um objeto Bird pode ser instanciado para um Duck ou um Cuckoo, Oberon-2 permite que o programador responda ao tipo real do objeto em tempo de execução.
A primeira abordagem, a mais convencional, é contar com o sistema de vinculação de tipo . A segunda abordagem é usar a WITH
instrução , que permite que o subtipo dinâmico de uma variável seja verificado diretamente. Em ambos os casos, uma vez que o subtipo tenha sido identificado, o programador pode fazer uso de quaisquer procedimentos ou variáveis vinculados ao tipo que sejam apropriados para o subtipo. Exemplos dessas abordagens são mostrados abaixo.
Observe que a forma de WITH
declaração usada em Oberon-2 não está relacionada à declaração Pascal e Modula-2 WITH. Este método de abreviar o acesso aos campos de registro não é implementado em Oberon ou Oberon-2.
Tipo de ligação
MODULE Birds;
TYPE
Bird* = RECORD
sound* : ARRAY 10 OF CHAR;
END;
END Birds.
MODULE Ducks;
IMPORT Birds;
TYPE
Duck* = RECORD (Birds.Bird) END;
PROCEDURE SetSound* (VAR bird : Duck);
BEGIN
bird.sound := "Quack!"
END SetSound;
END Ducks.
MODULE Cuckoos;
IMPORT Birds;
TYPE
Cuckoo* = RECORD (Birds.Bird) END;
PROCEDURE SetSound* (VAR bird : Cuckoo);
BEGIN
bird.sound := "Cuckoo!"
END SetSound;
END Cuckoos.
WITH
demonstração
MODULE Test;
IMPORT Out, Birds, Cuckoos, Ducks;
TYPE
SomeBird* = RECORD (Birds.Bird) END;
VAR
sb : SomeBird;
c : Cuckoos.Cuckoo;
d : Ducks.Duck;
PROCEDURE SetSound* (VAR bird : Birds.Bird);
BEGIN
WITH bird : Cuckoos.Cuckoo DO
bird.sound := "Cuckoo!"
| bird : Ducks.Duck DO
bird.sound := "Quack!"
ELSE
bird.sound := "Tweet!"
END
END SetSound;
PROCEDURE MakeSound* (VAR b : Birds.Bird);
BEGIN
Out.Ln;
Out.String(b.sound);
Out.Ln
END MakeSound;
BEGIN
SetSound(c);
SetSound(d);
SetSound(sb);
MakeSound(c);
MakeSound(d);
MakeSound(sb)
END Test.
POINTER
MODULE PointerBirds;
IMPORT Out;
TYPE
BirdRec* = RECORD
sound* : ARRAY 10 OF CHAR;
END;
DuckRec* = RECORD (BirdRec) END;
CuckooRec* = RECORD (BirdRec) END;
Bird = POINTER TO BirdRec;
Cuckoo = POINTER TO CuckooRec;
Duck = POINTER TO DuckRec;
VAR
pb : Bird;
pc : Cuckoo;
pd : Duck;
PROCEDURE SetDuckSound* (bird : Duck);
BEGIN
bird.sound := "Quack!"
END SetDuckSound;
PROCEDURE SetCuckooSound* (bird : Cuckoo);
BEGIN
bird.sound := "Cuckoo!"
END SetCuckooSound;
PROCEDURE SetSound* (bird : Bird);
BEGIN
WITH bird : Cuckoo DO
SetCuckooSound(bird)
| bird : Duck DO
SetDuckSound(bird)
ELSE
bird.sound := "Tweet!"
END
END SetSound;
BEGIN
NEW(pc);
NEW(pd);
SetCuckooSound(pc);
SetDuckSound(pd);
Out.Ln; Out.String(pc^.sound); Out.Ln;
Out.Ln; Out.String(pd^.sound); Out.Ln;
SetSound(pc);
SetSound(pd);
Out.Ln; Out.String(pc^.sound); Out.Ln;
Out.Ln; Out.String(pd^.sound); Out.Ln;
(* -------------------------------------- *)
(* Pass dynamic type to procedure *)
pb := pd;
SetDuckSound(pb(Duck));
Out.Ln; Out.String(pb^.sound); Out.Ln;
pb := pc;
SetCuckooSound(pb(Cuckoo));
Out.Ln; Out.String(pb^.sound); Out.Ln;
(* -------------------------------------- *)
SetSound(pb);
Out.Ln; Out.String(pb^.sound); Out.Ln;
pb := pd;
SetSound(pb);
Out.Ln; Out.String(pb^.sound); Out.Ln;
(* -------------------------------------- *)
NEW(pb);
SetSound(pb);
Out.Ln; Out.String(pb^.sound); Out.Ln
END PointerBirds.
IS
operador
Uma terceira abordagem é possível usando o IS
operador . Este é um operador de relação com a mesma precedência que equals ( =
), maior ( >
), etc., mas que testa o tipo dinâmico. Ao contrário das outras duas abordagens, no entanto, ele não permite que o programador acesse o subtipo que foi detectado.
Sintaxe
O desenvolvimento da família de linguagem ALGOL → Pascal → Modula-2 → Oberon → Componente Pascal é marcado por uma redução na complexidade da sintaxe da linguagem . Toda a linguagem Oberon-2 é descrita ( Mössenböck & Wirth, março de 1995 ) usando apenas 33 produções gramaticais na forma Backus-Naur estendida , como mostrado abaixo.
Module = MODULE ident ";" [ImportList] DeclSeq [BEGIN StatementSeq] END ident ".".
ImportList = IMPORT [ident ":="] ident {"," [ident ":="] ident} ";".
DeclSeq = { CONST {ConstDecl ";" } | TYPE {TypeDecl ";"} | VAR {VarDecl ";"}} {ProcDecl ";" | ForwardDecl ";"}.
ConstDecl = IdentDef "=" ConstExpr.
TypeDecl = IdentDef "=" Type.
VarDecl = IdentList ":" Type.
ProcDecl = PROCEDURE [Receiver] IdentDef [FormalPars] ";" DeclSeq [BEGIN StatementSeq] END ident.
ForwardDecl = PROCEDURE "^" [Receiver] IdentDef [FormalPars].
FormalPars = "(" [FPSection {";" FPSection}] ")" [":" Qualident].
FPSection = [VAR] ident {"," ident} ":" Type.
Receiver = "(" [VAR] ident ":" ident ")".
Type = Qualident
| ARRAY [ConstExpr {"," ConstExpr}] OF Type
| RECORD ["("Qualident")"] FieldList {";" FieldList} END
| POINTER TO Type
| PROCEDURE [FormalPars].
FieldList = [IdentList ":" Type].
StatementSeq = Statement {";" Statement}.
Statement = [ Designator ":=" Expr
| Designator ["(" [ExprList] ")"]
| IF Expr THEN StatementSeq {ELSIF Expr THEN StatementSeq} [ELSE StatementSeq] END
| CASE Expr OF Case {"|" Case} [ELSE StatementSeq] END
| WHILE Expr DO StatementSeq END
| REPEAT StatementSeq UNTIL Expr
| FOR ident ":=" Expr TO Expr [BY ConstExpr] DO StatementSeq END
| LOOP StatementSeq END
| WITH Guard DO StatementSeq {"|" Guard DO StatementSeq} [ELSE StatementSeq] END
| EXIT
| RETURN [Expr]
].
Case = [CaseLabels {"," CaseLabels} ":" StatementSeq].
CaseLabels = ConstExpr [".." ConstExpr].
Guard = Qualident ":" Qualident.
ConstExpr = Expr.
Expr = SimpleExpr [Relation SimpleExpr].
SimpleExpr = ["+" | "-"] Term {AddOp Term}.
Term = Factor {MulOp Factor}.
Factor = Designator ["(" [ExprList] ")"] | number | character | string | NIL | Set | "(" Expr ")" | " ~ " Factor.
Set = "{" [Element {"," Element}] "}".
Element = Expr [".." Expr].
Relation = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
AddOp = "+" | "-" | OR.
MulOp = "*" | "/" | DIV | MOD | "&".
Designator = Qualident {"." ident | "[" ExprList "]" | " ^ " | "(" Qualident ")"}.
ExprList = Expr {"," Expr}.
IdentList = IdentDef {"," IdentDef}.
Qualident = [ident "."] ident.
IdentDef = ident [" * " | " - "].
Implementações
Os compiladores Oberon-2 mantidos pela ETH incluem versões para Windows , Linux , Solaris , macOS .
O compilador Oxford Oberon-2 compila em código de máquina nativo e pode usar um JIT no Windows, Linux e Mac OS X. Ele é criado / mantido por Mike Spivey e usa a Máquina Virtual Keiko .
Há um scanner Oberon-2 Lex e analisador Yacc de Stephen J. Bevan da Universidade de Manchester, no Reino Unido, baseado no da referência Mössenböck e Wirth. Ele está na versão 1.4.
Existe uma versão chamada Native Oberon que inclui um sistema operacional e pode inicializar diretamente em hardware de classe de PC.
Uma implementação .NET do Oberon com a adição de algumas extensões menores relacionadas ao .NET também foi desenvolvida na ETHZ.
Programmer's Open Workbench (POW!) É um ambiente de desenvolvimento integrado muito simples, que é fornecido com editor, vinculador e compilador Oberon-2. Compila para executáveis do Windows . O código-fonte completo é fornecido; o compilador é escrito em Oberon-2.
O Java to Oberon Compiler (JOB) foi escrito na Universidade de Vologda, na Rússia. Ele produz código-objeto na forma de arquivos de classe Java ( bytecode ). Algumas classes específicas de JOB são fornecidas, as quais são compatíveis com Java, mas usam uma hierarquia de componentes mais semelhante a Oberon.
O compilador Optimizing Oberon-2 compila em C, usando a cadeia de ferramentas GNU Compiler Collection (GCC) para geração de programa.
Oberon Script é um compilador que traduz toda a linguagem Oberon para JavaScript . O compilador é escrito em JavaScript e, portanto, pode ser chamado de páginas da Web para processar scripts escritos em Oberon.
XDS Modula2 / Oberon2 é um sistema de desenvolvimento da Excelsior LLC, Novosibirsk, Rússia. Ele contém um compilador de otimização para Intel Pentium ou tradutor "via-C" para desenvolvimento de software de plataforma cruzada . Disponível para Windows e Linux. O compilador é escrito em Oberon-2 e compila a si mesmo.
Oberon Revival é um projeto para trazer Oberon 2 e Component Pascal ( BlackBox Component Builder ) para Linux e Win32. A porta Linux do BlackBox não estava disponível antes e rodava originalmente apenas no Microsoft Windows.
XOberon é um sistema operacional em tempo real para PowerPC , escrito em Oberon-2.
Veja também
Referências
Evolução de Oberon e Oberon-2
- " Oberon Language Genealogy Tree " mantida na ETHZ
- "Segunda Conferência Internacional Modula-2", setembro de 1991.
Papéis detalhados
- De Modula a Oberon Wirth (1990)
- Programação em Oberon - Um derivado de Programação em Modula-2 Wirth (1982)
- The Programming Language Oberon Wirth (1990)
- Relatório Oberon 2
- The Programming Language Oberon-2 H. Mössenböck, N. Wirth, Institut für Computersysteme, ETH Zurich , janeiro de 1992 e Structured Programming (1991) 12 (4): 179-195.
Livros
- Várias referências, incluindo versões eletrônicas online
- Programação Orientada a Objetos em Oberon-2 Hanspeter Mössenböck (1994). (Disponível na Johannes Kepler University como PDF com a permissão da Springer-Verlag)
- Padrões de projeto em Oberon-2 e Component Pascal
- Projeto Oberon. O projeto de um sistema operacional e compilador Niklaus Wirth & Jürg Gutknecht (2005)
- Projeto Oberon. O projeto de um sistema operacional e compilador Niklaus Wirth & Jürg Gutknecht (2013)