A primeira parte com requisitos funcionais está
aqui .
Reivindicada como linguagens de programação com foco na confiabilidade.
Alfabeticamente - Oberon ativo, Ada, BetterC, IEC 61131-3 ST, Safe-C.
Ao mesmo tempo, a isenção de responsabilidade (desculpa) não é de forma alguma uma campanha "do lado esquerdo", e a revisão é bastante acadêmica - o idioma pode não apenas ter um ambiente de desenvolvimento moderno com suporte ativo, mas também um compilador para sua plataforma.
Por outro lado, para os idiomas em questão, existem compiladores de código aberto e, com o nível atual de desenvolvimento de software - com interesse, a sintaxe não é muito complicada, permite criar um compilador pessoal e integrar-se a algum tipo de Eclipse com luz de fundo e analisador.
Como indicador da clareza da linguagem, escolhi a implementação da famosa tarefa multiencadeada de Dijkstra sobre os filósofos do jantar. A implementação está nos livros didáticos sobre o idioma e nos fóruns, o que facilitou meu trabalho - resta apenas me adaptar. Por exemplo, um
artigo recente do
habr sobre C ++ moderno contém uma implementação no C ++ 17 para comparação.
Oberon ativo (2004)
Foi criado tendo em vista a experiência de Pascal, Modula, Oberons anteriores desde 1988, Java, C #, Ada, além de experiência prática em aplicação. Possui uma implementação na forma do
OS A2 , que pode atuar como tempo de execução em cima de * nix ou Windows.
Fontes A2 e o compilador para o link .
Há também um projeto
Oberon2 para C Compiler (OOC) que não
está vinculado ao ambiente Oberon. Este é um dialeto ligeiramente diferente, as diferenças são descritas abaixo.
A principal característica do Oberon é a excepcional brevidade da especificação. São 16 páginas no Oberon-2 base mais 23 páginas na extensão Active multithread.
Sintaxe simples e clara que exclui erros óbvios.
Identificadores diferenciam maiúsculas de minúsculas.
OOP com objetos na pilha com o coletor de lixo (GC).
Ele difere de seus antecessores na sintaxe OOP mais familiar na forma de Instance.Method (costumava ser Method (Instance)) e suporta multithreading com primitivas de sincronização.
Não há despacho dinâmico na implementação do OOP, o que pode facilmente levar a uma situação - eles esqueceram de adicionar processamento para um novo tipo.
É possível atribuir prioridade aos fluxos e, em tempo real / alto, eles não são interrompidos pelo GC. Strings na forma de matrizes UTF-8.
O Rantime (Oberon System) oferece oportunidades interessantes para reiniciar um procedimento / módulo / thread com falha no caso de um erro de tempo de execução - endereçamento de memória ou, por exemplo, estouro de número inteiro.
A desvantagem é a falta de RAII e o tratamento conveniente de erros - tudo através de códigos de retorno, com exceção da opção abaixo.
Oberon-2 OOC
É mais conveniente para experimentos, já que o Oberon não requer SO - ele é compilado no ANSI C e não há problemas de interoperabilidade. Diferenças da versão ativa - não há linguagem multithreading integrada -, em vez disso, existe um módulo para trabalhar com PThreads, mas há UTF16, modularidade hierárquica e um módulo de sistema para trabalhar com exceções.
Módulo 3
Há também um parente de um ramo de desenvolvimento ligeiramente diferente na forma de Modula-3. Foi criado com base em Oberon, em oposição ao Ada superdesenvolvido.
A implementação está aqui .
Comparado ao Active Oberon, são adicionados genéricos e exceções, existem bibliotecas para trabalhos práticos com Unicode, GUI e até Postgress. Integração simplificada com C. Outras semânticas multithreading. RAII como WITH (semelhante ao uso em C #).
Mas parece que o desenvolvimento do Módulo 3 parou em 2010.
Isenção de responsabilidade. Após iniciar o WinAOS, deparei-me com TRAPs (também conhecido como abort / stacktrace ou erro de tempo de execução) - mesmo o gerenciador de tarefas não funciona corretamente e, embora o sistema / tempo de execução não tenha travado - mas apenas o aplicativo, eu tinha uma certa dúvida de que a confiabilidade é determinada pelo idioma programação = (
Além disso, o AOC é suficientemente independente, com sua abordagem de desenvolvimento.
Fonte para filósofos de jantarMODULE Philo; IMPORT Semaphores := Example8, Out; CONST NofPhilo = 5; VAR fork: ARRAY NofPhilo OF Semaphores.Semaphore; i: LONGINT; TYPE Philosopher = OBJECT VAR first, second: LONGINT; PROCEDURE & Init(id: LONGINT); BEGIN IF id # NofPhilo-1 THEN first := id; second := (id+1) ELSE first := 0; second := NofPhilo-1 END END Init; PROCEDURE Think; BEGIN Out.Int(first); Out.String(".... Think...."); Out.Ln; END Think; PROCEDURE Eat; BEGIN Out.Int(first); Out.String(".... Eat...."); Out.Ln; END Eat; BEGIN LOOP Think; fork[first].P; fork[second].P; Eat; fork[first].V; fork[second].V END END Philosopher; VAR philo: ARRAY NofPhilo OF Philosopher; BEGIN FOR i := 0 TO NofPhilo DO NEW(fork[i], INTEGER(i)); NEW(philo[i], i); END; END Philo. Philo.Philo1 ~
Ada (1980, último padrão válido de 2016)
Na verdade, à primeira vista, há tudo o que eu gostaria.
E um pouco mais - existem números com cálculos exatos de ponto flutuante. Por exemplo, há um agendador de encadeamentos em tempo real, troca de encadeamentos e um subconjunto verificado formalmente da linguagem SPARK. E muito mais
Eu acho que se a confiabilidade de Ada precisasse de um chifre, seria anexada com instruções para chamar em uma situação difícil =)
Implementação -
GNUTaya Ada , está em desenvolvimento, padronizado ISO / IEC.
O padrão fornece implementação com GC, mas para opções compiladas, geralmente não é implementado. É necessário gerenciamento manual de memória - e aqui são possíveis erros do programador. No entanto, o idioma é voltado para o uso da pilha padrão e existe o conceito de tipos gerenciados com destruidores. Você também pode definir sua implementação, liberação automática ou contagem de referência do GC para cada tipo de dados.
O Ada Reference Manual 2012 contém 950 páginas.
A desvantagem de Ada, além da complexidade, é sua excessiva verbosidade, que, no entanto, foi concebida para facilitar a leitura. Devido à especificidade do modelo de segurança de idiomas, a integração com bibliotecas estrangeiras é difícil.
O
site Ada-ru possui um bom artigo de tradução de resenhas - o primeiro link.
Fonte para filósofos de jantar BetterC (subconjunto dlang 2017, original D - 2001, D 2.0 - 2007)
A implementação mais moderna do considerado. A descrição completa do idioma é bastante longa - 649 páginas -
veja o site original .
Na verdade, esse é o idioma D, mas com restrições com a opção -betterC. Por que ?!
Como a biblioteca padrão D é Phobos, desenvolvida pela Alexandrescu e acabou sendo muito esperta, completamente construída em modelos. A chave para este tópico é que o Phobos é incontrolável em termos de consumo de memória.
As coisas mais importantes que se perdem no modo BetterC são multithreading, GC, strings, classes (estruturas permanecem - elas têm funcionalidade estreita - apenas na pilha) e exceções (RAII e try-finalmente permanecem).
É possível, no entanto, escrever parte do programa em D completo e a parte crítica em D-BetterC. Há também uma função de atributo do sistema para controlar o não uso de efeitos perigosos: pure
safe @nogc.
Justificação do regime do criador da língua.
E
então o aperto - o que é cortado e o que permanece disponível.
As strings estão contidas no Phobos - e as tentativas de usá-las no BetterC resultam em erros infernais de instanciação de modelos em operações elementares, como a saída de uma string no console ou concatenação. E no modo D completo, as linhas na pilha também são imutáveis, portanto, as operações com elas levam à confusão de memória.
Eu tive que atender a reclamações sobre erros no compilador várias vezes. O que, no entanto, não é surpreendente para uma linguagem que compete em complexidade com C ++. Ao preparar o artigo, eu também tive que enfrentar quatro erros - dois surgiram ao tentar criar o dlangide com um novo compilador e alguns ao portar o problema do filósofo (por exemplo, travar ao usar o beginthreadex).
O modo apareceu recentemente e os erros causados pela restrição do modo BetterC já são divulgados no estágio de vinculação. Para aprender sobre isso com antecedência, quais recursos do idioma são aparados exatamente - geralmente precisam ser feitos em primeira mão.
Fonte para filósofos de jantar Para comparação, a fonte está cheia D.Na roseta, você também pode ver opções para outros idiomas.
IEC 61131-3 ST (1993, última norma 2013)
Uma linguagem de programação de nicho para microcontroladores. O padrão implica 5 opções de programação, mas escrever um aplicativo, por exemplo, em lógica ladder ainda é uma aventura. Portanto, focamos em uma opção - texto estruturado.
O texto da norma GOST R IEC 61131-3-2016 - 230 páginas.
Existem implementações para PC / x86 e ARM - e comerciais, a mais famosa delas é a
CODESYS (geralmente também sublicenciada com nomes diferentes) e a transmissão
aberta - Beremiz - via C.
Como existe integração com C, é bem possível conectar as bibliotecas necessárias para a programação aplicada. Por outro lado, nessa área, é aceito que a lógica gire separadamente e sirva apenas como servidor de dados para outro programa ou sistema - uma interface com um operador ou um DBMS que já possa ser gravado em qualquer coisa - sem requisitos em tempo real ou mesmo temporários em geral ...
A programação multithread para um programa de usuário apareceu relativamente recentemente - em microcontroladores isso não era necessário antes.
A conversão de tipos é principalmente explícita (relaxada no padrão mais recente). Mas o controle de estouro depende da implementação.
Na última edição do padrão, OOP apareceu. O tratamento de erros é feito por manipuladores de interrupção personalizados.
Podemos dizer que não há alocação dinâmica de memória para o usuário. Isso aconteceu historicamente - a quantidade de dados processados pelo microcontrolador é sempre constante limitada acima.
Fonte (não confirmada) Philo_2: Philosopher; Philo_3: Philosopher; Philo_4: Philosopher; Philo_5: Philosopher; END_VAR RESOURCE Station_1 ON CPU_1 TASK Task_1 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_2 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_3 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_4 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_5 (INTERVAL := T#100MS, PRIORITY := 1); PROGRAM Life_1 WITH Task_1: Philo_1(Name := 'Kant', 0, 1, Forks); PROGRAM Life2 WITH Task_2: Philo_2(Name := 'Aristotel', 1, 2, Forks); PROGRAM Life3 WITH Task_3: Philo_3(Name := 'Spinoza', 2, 3, Forks); PROGRAM Life4 WITH Task_4: Philo_4(Name := 'Marx', 3, 4, Forks); PROGRAM Life5 WITH Task_5: Philo_5(Name := 'Russel', 4, 0, Forks); END_RESOURCE END_CONFIGURATION FUNCTION_BLOCK Philosopher; USING SysCpuHandling.library; VAR_INPUT Name: STRING; Left: UINT; Right: UINT; END_VAR VAR_IN_OUT Forks: USINT; END_VAR VAR Thinking: BOOL := TRUE; Hungry: BOOL; Eating: BOOL; HaveLeftFork: BOOL; TmThink: TON; TmEating: TON; END_VAR TmThink(In := Thinking; PT := T#3s); TmEating(In := Eating; PT := T#5s); IF Thinking THEN Thinking := NOT TmThink.Q; Hungry := TmThink.Q; ELSIF Hungry IF HaveLeftFork IF SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Right, bSet := 1) = ERR_OK THEN Hungry := FALSE; Eating := TRUE; ELSE RETURN; END_IF ELSIF IF SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Left, bSet := 1) = ERR_OK THEN HaveLeftFork := TRUE; ELSE RETURN; END_IF END_IF ELSIF Eating IF TmEating.Q THEN Thinking := TRUE; Eating := FALSE; HaveLeftFork := FALSE; SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Right, bSet := 0); SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Left, bSet := 0); END_IF END_IF END_FUNCTION_BLOCK
Safe-C (2011)
Experimental C com a remoção de chips perigosos e com a adição de modularidade e multithreading.
Site do projetoDescrição de aproximadamente 103 páginas. Se você destacar as diferenças de C -
muito pouco, cerca de 10 .
Trabalhar com matrizes e ponteiros é uma memória segura e dinâmica, com contagem automática de referências - com verificações de liberação dupla e links pendentes.
A biblioteca padrão possui um conjunto mínimo de funções para a GUI, multithreading, funções de rede (incluindo um servidor http).
Mas - esta implementação é apenas para Windows x86. Embora o código do compilador e da biblioteca esteja aberto.
Como parte de outra tarefa de pesquisa, montei um layout de servidor da Web que coleta dados dos sensores da IoT: um módulo executivo de 75 Kb e um conjunto de memória parcial <1 MB.
Fonte para filósofos de jantar from std use console, thread, random; enum philos (ushort) { Aristotle, Kant, Spinoza, Marx, Russell, }; const int cycles = 10; const ushort NUM = 5; uint lived = NUM; packed struct philosopher // 32-bit { philos name; byte left, right; } philosopher philo_body[NUM]; SHARED_OBJECT forks[NUM]; void philosopher_life(philosopher philo) { int age; for (age = 0; age++ < cycles; ) { printf("%s is thinking\n", philo.name'string); delay((uint)rnd(1, 100)); printf("%s is hungry\n", philo.name'string); enter_shared_object(ref forks[philo.left]); enter_shared_object(ref forks[philo.right]); printf("%s is eating\n", philo.name'string); delay((uint)rnd(1, 100)); leave_shared_object(ref forks[philo.right]); leave_shared_object(ref forks[philo.left]); } printf("%s is leaving\n", philo.name'string); InterlockedExchange(ref lived, lived-1); } void main() { philos i; assert philosopher'size == 4; philo_body[0] = {Aristotle, 0, 1}; philo_body[1] = {Kant, 1, 2}; philo_body[2] = {Spinoza, 2, 3}; philo_body[3] = {Marx, 3, 4}; philo_body[4] = {Russell, 0, 4}; for (i = philos'first; i <= philos'last; i++) { assert run philosopher_life(philo_body[(uint)i]) == 0; } while (lived > 0) sleep 0;
Finalmente - uma
tabela resumida de conformidade com os requisitos funcionais.
Certamente eu perdi ou interpretei algo errado - então corrija-o.
Fontes do artigo no github .