Oberon-2 - Oberon-2

Oberon-2
Oberon programming language logo.svg
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 ; 30 anos atrás ( 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 .ethoberon .ethz .ch
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 FORdeclaraçã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 WITHinstruçã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 WITHdeclaraçã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 ISoperador . 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 ALGOLPascalModula-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

Papéis detalhados

Livros

links externos