UNIVERSIDADE ANHEMBI MORUMBI
DÊNIO ROBSON VAL SILVA
FELIPE BARATOJO FLORES
NEIDE SOARES SALES
LINGUAGEM DE PROGRAMAÇÃO INTERPRETADA UTILIZADA
NA CONFIGURAÇÃO DE APLICATIVOS VOLTADOS PARA
SISTEMAS MULTI-PLATAFORMA COM IMPLEMENTAÇÃO EM
AMBIENTE PARAVIRTUALIZADO
São Paulo
2010
DÊNIO ROBSON VAL SILVA
FELIPE BARATOJO FLORES
NEIDE SOARES SALES
LINGUAGEM DE PROGRAMAÇÃO INTERPRETADA
UTILIZADA NA CONFIGURAÇÃO DE APLICATIVOS
VOLTADOS PARA SISTEMAS MULTI-PLATAFORMA COM
IMPLEMENTAÇÃO EM AMBIENTE PARAVIRTUALIZADO
Orientador: Professor Msc. Luciano Freire
São Paulo
2010
Monografia apresentada como exigência parcial para a obtenção do
título de bacharel em Ciência da Computação pela Universidade
Anhembi Morumbi
UNIVERSIDADE ANHEMBI MORUMBI
BACHARELADO EM CIÊNCIA DA COMPUTAÇÃO
DÊNIO ROBSON VAL SILVA
FELIPE BARATOJO FLORES
NEIDE SOARES SALES
LINGUAGEM DE PROGRAMAÇÃO INTERPRETADA
UTILIZADA NA CONFIGURAÇÃO DE APLICATIVOS
VOLTADOS PARA SISTEMAS MULTI-PLATAFORMA COM
IMPLEMENTAÇÃO EM AMBIENTE PARAVIRTUALIZADO
Aprovado
______________________________________________________________________
Prof. Msc. Luciano Freire
Universidade Anhembi Morumbi
______________________________________________________________________
Prof................................
Universidade Anhembi Morumbi
______________________________________________________________________
Prof. ..............................
Universidade Anhembi Morumbi
Monografia apresentada como exigência parcial para a obtenção do
título de bacharel em Ciência da Computação pela Universidade
Anhembi Morumbi
UNIVERSIDADE ANHEMBI MORUMBI
Dedicamos este trabalho de conclusão de curso a todos os nossos
familiares que nos apoiaram, à Anhembi Morumbi por ter acreditado no
Curso Superior em Ciência da Computação e ao orientador, Professor
que, com dedicação e conhecimento, orientou-nos no decorrer deste
trabalho.
AGRADECIMENTOS
Agradecemos aos colegas que contribuíram e incentivaram para a realização deste
trabalho e também aos professores que com sabedoria nos acompanharam nestes anos
em que decorreu o curso e, em especial, ao nosso orientador que nos acompanhou em
todas as etapas deste trabalho. Também aos amigos e à família pela compreensão de
nossa ausência para a elaboração do mesmo.
“Nossas dúvidas são traidoras e nos fazem perder o que, com
freqüência, poderíamos ganhar, por simples medo de arriscar.”
(William Shakespeare)
RESUMO
Esta monografia apresenta um breve estudo sobre a tecnologia da virtualização
explorando os benefícios dos tipos de virtualização existentes, e principalmente da
paravirtualização, com o objetivo de desenvolver uma linguagem interpretada para ser
utilizada em aplicativos hospedeiros.
São praticamente inexistentes as linguagens de programação voltadas à
configuração e, embora a linguagem seja voltada a qualquer plataforma, a
implementação foi realizada em um ambiente paravirtualizado por facilitar a criação de
ambientes diversificados sem necessidade de hardware adicional, apresentando um
desempenho razoável.
Este trabalho não envolve a criação de um compilador, mas de uma linguagem,
na condição de linguagem de extensão aplicada ao software hospedeiro Asterisk e às
etapas para a implementação da mesma em um ambiente paravirtualizado.
Para o desenvolvimento deste trabalho, foi necessária a realização de um estudo
a respeito dos tipos de virtualização, através da análise de documentos da IBM, Xen,
VmWare e outros fabricantes importantes, para que então optássemos pela utilização do
Xen como software de virtualização.
Quatro etapas principais foram necessárias para a conclusão do trabalho: a
pesquisa a respeito das tecnologias existentes, tanto para virtualização como para
utilização da linguagem interpretada; a criação do ambiente paravirtualizado; a criação
da linguagem interpretada utilizada no aplicativo hospedeiro Asterisk e a junção do
ambiente virtualizado criado com a linguagem desenvolvida.
Palavras-Chave: Virtualização, Linguagem Interpretada, Xen, Asterisk.
ABSTRACT
This monograph presents a brief study about virtualization technology by
exploring the benefits of existing virtualization types, and mainly the paravirtualization
with the goal of developing an interpreted language to be used in host applications.
Practically it doesn’t exist programming languages directed to configuration and
although the language is geared to any platform, the implementation was done in a
paravirtualized environment by facilitating the creation of diversified environments
without requiring additional hardware and showing reasonable performance.
The work does not involve the creation of a compiler, but a language, as an
extension language applied to the host software Asterisk, and the steps to implement it
in a paravirtualized environment.
To develop the work was necessary to carry out a study about the types of
virtualization through documents from IBM, Xen, VmWare and other major
manufacturers to take back the conclusion that we should use the Xen virtualization
software.
Four main steps were necessary for completion of the work: research on existing
technologies, for both to use virtualization as the interpreted language; the creation of
paravirtualized environment; the creation of the interpreted language used in the host
application Asterisk, and the join of the virtualized environment created with the
language developed.
Key words: Virtualization, Interpreted Language, Xen, Asterisk.
LISTA DE FIGURAS
Figura 1 - Várias máquinas virtuais em um único hardware.......................................... 17
Figura 2 – Tecnologia com mais impacto na transformação dos processos de negócio 20
Figura 3 - Emulação de hardware................................................................................... 21
Figura 4 - Virtualização completa .................................................................................. 22
Figura 5 - Paravirtualização............................................................................................ 23
Figura 6 - Virtualização de sistema operacional ............................................................ 24
Figura 7 – VmWare ESX ............................................................................................... 28
Figura 8 – Componentes do Xen.................................................................................... 32
Figura 9 – User mode Linux........................................................................................... 33
Figura 10 - Linguagem interpretada............................................................................... 38
Figura 11 - Linguagem compilada.................................................................................. 40
Figura 12 – Instalação Xen............................................................................................. 44
Figura 13 – Instalando o Hypervisor e Ferramentas 1 ................................................... 45
Figura 14 – Domínio 0 configurado ............................................................................... 45
Figura 15 – Processo de inicialização............................................................................. 47
Figura 16 – Tratamento de chamada .............................................................................. 47
Figura 17 – Compilação do módulo ............................................................................... 48
Figura 18 – Diretório de módulos do Asterisk ............................................................... 48
Figura 19 – Arquivo sip.conf.......................................................................................... 51
Figura 20 – Topologia final............................................................................................ 59
Figura 21 – Módulo carregado com sucesso .................................................................. 60
Figura 22 – Módulo não carrega sem extensions.dfn..................................................... 60
Figura 23 – CDR ............................................................................................................ 61
Figura 24 – Ligação realizada ........................................................................................ 62
LISTA DE TABELAS
Tabela 1 – Ferramentas de virtualização.........................................................................26
Tabela 2 – Suporte Xen 3.0.............................................................................................30
Tabela 3 – Suporte Xen 2.0.............................................................................................31
Tabela 4 – Tipos de linguagens.......................................................................................35
LISTA DE ABREVIATURAS E SIGLAS
AMD – Advanced Micro Devices
AMD-V – Advanced Micro Devices Virtualization
API (Application Programming Interface): Interface de Programação de Aplicações
BIOS (Basic Input/Output System): Sistema básico de entrada/saída
CD-ROM (Compact Disk Read Only Memory): Disco Compacto com Memória
somente leitura
CMS – Conversational Monitor System
CPU (Central Processing Unit): Unidade de Processamento Central
GHz – Gigahertz
HD (Hard Disk): Disco Rígido
IAX – Inter Asterisk Exchange
IBM – International Business Machines
IDC – International Data Corporation
IDE (Integrated Development Environment): Ambiente de Desenvolvimento Integrado
IETF – Internet Engineering Task Force
Intel-VT (Intel Virtualization Technology): Tecnologia de Virtualização da Intel
KVM – Kernel-based Virtual Machine
MGCP – Media Gateway Control Protocol
MIT – Massachusetts Institute of Technology
PBX – Private Branch Exchanges
PSTN – Public Switched Telephone Network
RAM (Random Access Memory): Memória de Acesso Aleatório
SIP – Session Initiation Protocol
SLA (Service Level Agreement): Acordo de Nível de Serviço
TCP – Transmission Control Protocol
TI – Tecnologia da Informação
UDP – User Datagram Protocol
UML – User Mode Linux
USB – Universal Serial Bus
VBS – Visual Basic Script
VGA – Video Graphics Array
VM (Virtual Machine): Máquina Virtual
VMM (Virtual Machine Monitor): Monitor de Máquina Virtual
VoIP (Voice over IP): Voz Sobre IP
VT (Virtualization Technology): Tecnologia de Virtualização
SUMÁRIO
1 INTRODUÇÃO...................................................................................................................... 15
1.1 OBJETIVOS ..................................................................................................................... 15
1.2 JUSTIFICATIVA.............................................................................................................. 15
1.3 ABRANGÊNCIA.............................................................................................................. 16
1.4 ESTRUTURA DO TRABALHO...................................................................................... 16
2 VIRTUALIZAÇÃO ............................................................................................................... 17
2.1 INTRODUÇÃO SOBRE VIRTUALIZAÇÃO................................................................. 17
2.2 HISTÓRIA DA VIRTUALIZAÇÃO................................................................................ 18
2.3 NECESSIDADE DA VIRTUALIZAÇÃO ....................................................................... 19
2.4 EMULAÇÃO DE HARDWARE...................................................................................... 21
2.5 VIRTUALIZAÇÃO COMPLETA.................................................................................... 22
2.6 PARAVIRTUALIZAÇÃO................................................................................................ 23
2.7 VIRTUALIZAÇÃO DE SISTEMA OPERACIONAL..................................................... 24
2.8 HARDWARE COM SUPORTE À VIRTUALIZAÇÃO ................................................. 24
3 FERRAMENTAS PARA VIRTUALIZAÇÃO.................................................................... 26
3.1 BOCHS ............................................................................................................................. 26
3.2 QEMU............................................................................................................................... 27
3.3 VMWARE......................................................................................................................... 27
3.4 LINUX KVM.................................................................................................................... 29
3.5 HYPER-V ......................................................................................................................... 29
3.6 XEN................................................................................................................................... 29
3.7 UML.................................................................................................................................. 33
4 ASTERISK.............................................................................................................................. 35
4.1 SIP..................................................................................................................................... 35
4.2 MGCP ............................................................................................................................... 36
4.3 IAX.................................................................................................................................... 36
5. LINGUAGENS DE PROGRAMAÇÃO.............................................................................. 37
5.1 LINGUAGENS INTERPRETADAS................................................................................ 38
5.1.1 LINGUAGEM DE EXTENSÃO OU SCRIPT.......................................................... 39
5.2 LINGUAGENS COMPILADAS ...................................................................................... 40
6 METODOLOGIA .................................................................................................................. 41
6.1 VIRTUALIZAÇÃO .......................................................................................................... 41
6.2 LINGUAGEM INTERPRETADA ................................................................................... 42
6.3 TESTES FINAIS............................................................................................................... 42
7 DESENVOLVIMENTO ........................................................................................................ 44
7.1 CONFIGURAÇÃO DO AMBIENTE............................................................................... 44
7.2 DETALHES DE IMPLEMENTAÇÃO DA PARAVIRTUALIZAÇÃO ......................... 44
7.3 INSTALAÇÃO ASTERISK ............................................................................................. 46
7.3.1 INTERAÇÃO ENTRE O ASTERISK E O MÓDULO DA LINGUAGEM DFN ..... 47
7.4 DESENVOLVIMENTO DA LINGUAGEM INTERPRETADA PARA SISTEMA
MULTI-PLATAFORMA........................................................................................................ 51
7.4.1 VARIÁVEIS E TIPOS............................................................................................... 52
7.4.2 ATRIBUIÇÕES ......................................................................................................... 53
7.4.3 OPERADORES ARITMÉTICOS E RELACIONAIS............................................... 53
7.4.4 ORDEM DE PRECEDÊNCIA DOS OPERADORES............................................... 54
7.4.5 COMENTÁRIOS....................................................................................................... 54
7.4.6 FUNÇÕES DA LINGUAGEM.................................................................................. 54
7.4.6.1 FUNÇÕES DE MANIPULAÇÃO DE STRING.................................................... 54
7.4.7 CONTROLE DE FLUXO E LAÇOS ITERATIVOS................................................ 56
7.4.7.1 TOMADAS DE DECISÃO COM IF.................................................................... 56
7.4.7.2 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO INÍCIO (WHILE) 57
7.4.7.3 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO FIM
(REPEAT/UNTIL).............................................................................................................. 57
7.4.8 ANALISADOR DE EXPRESSÃO............................................................................ 58
7.5 IMPLEMENTAÇÃO DA LINGUAGEM INTERPRETADA NO SISTEMA
PARAVIRTUALIZADO ........................................................................................................ 59
8 CONCLUSÃO ....................................................................................................................... 63
REFERÊNCIAS BIBLIOGRÁFICAS .................................................................................... 64
APÊNDICE A – CÓDIGO FONTE DA LINGUAGEM ....................................................... 68
APÊNDICE B – ARQUIVOS DE CONFIGURAÇÃO DO ASTERISK E MÓDULO DE
CARGA.................................................................................................................................... 143
APÊNDICE C – ARQUIVO DE CONFIGURAÇÃO DO XEN ......................................... 147
15
1 INTRODUÇÃO
A virtualização possibilita a definição de diversas máquinas lógicas em apenas um
único hardware, fazendo com que a utilização de recursos aumente, além de facilitar a
consolidação e segurança de ambientes computacionais.
Segundo Bernard Golden e Clark Scheffy (2008, p.06 e 07), muitos data centers
possuem máquinas sendo utilizadas com apenas 10% a 15% de sua capacidade total de
processamento e, além disso, a necessidade de máquinas distintas para aplicações
diferentes aumenta ainda mais a infra-estrutura, dificultando a administração,
aumentando os gastos com manutenção, gerenciamento e energia.
Uma linguagem de programação interpretada como linguagem de extensão permite
a utilização de aplicativos hospedeiros em ambiente multi-plataforma, pois esta não está
vinculada à linguagem de máquina do ambiente e sim ao interpretador.
A razão para o desenvolvimento deste trabalho baseia-se no fato de que hoje em dia
são praticamente inexistentes linguagens de programação voltadas à configuração de
aplicativos que exijam agilidade na administração, alta disponibilidade e resiliência.
Alguns aplicativos já possuem essa tecnologia, como por exemplo, o software de
PBX VoIP Asterisk, que pode fazer uso de linguagens de extensão como alternativa à
utilização de arquivos de configuração para facilitar seu uso e administração.
1.1 OBJETIVOS
O objetivo deste trabalho é desenvolver uma linguagem de programação
interpretada (extensível) para permitir maior flexibilidade na parametrização de
aplicativos que necessitem do uso de configuração para o seu funcionamento. Como
exemplo, esta linguagem será voltada para o software Asterisk. Será utilizada a
paravirtualização como ambiente de implementação do Asterisk e da linguagem
desenvolvida facilitando a administração e possibilitando um SLA (Service Level
Agreement) elevado.
1.2 JUSTIFICATIVA
A justificativa deste trabalho consiste nas dificuldades práticas em criar ambientes
configuráveis de forma flexível. São praticamente inexistentes as linguagens de
programação voltadas à configuração, principalmente no âmbito dos sistemas
embarcados. Esta linguagem, ou mais precisamente, interpretador, é direcionado a
qualquer plataforma. Entretanto, neste trabalho a implementação será realizada em um
16
ambiente paravirtualizado, visto que a paravirtualização é uma tecnologia que facilita a
criação de ambientes diversificados, sem a necessidade de adquirir hardwares com
suporte a virtualização, além de facilitar a implementação de máquinas adicionais com
sistemas que podem ou não estar integrados uns com os outros e com confiabilidade.
1.3 ABRANGÊNCIA
Este trabalho abrange o desenvolvimento da linguagem na forma de interpretador na
condição de linguagem de extensão, que será implementada em um ambiente
paravirtualizado. Não faz parte do escopo deste trabalho o desenvolvimento de um
compilador, mas sim de uma linguagem que possa ser embutida em outros aplicativos,
que neste caso será no software Asterisk. O próprio software Asterisk é quem agirá
como interpretador. Embora a virtualização não seja uma condição obrigatória para o
uso da linguagem, ela será utilizada na implementação da solução, dada sua
flexibilidade.
1.4 ESTRUTURA DO TRABALHO
A estrutura do trabalho está dividida nos seguintes capítulos:
O capítulo 2 aborda a definição de virtualização e as técnicas existentes.
O capítulo 3 aborda a explicação das ferramentas de virtualização mais
conhecidas no mercado, tanto as livres quanto as pagas.
O capítulo 4 mostra o que é o Asterisk e suas principais características.
O capítulo 5 trata do conceito de linguagem interpretada com exemplos de
aplicação.
O capítulo 6 aborda a metodologia do trabalho.
O capítulo 7 mostra a criação do ambiente paravirtualizado em preparação para
implementação da linguagem interpretada, assim como os detalhes da criação da
linguagem e utilização da API do Asterisk para que este entenda e interprete a
linguagem desenvolvida. Além disso, haverá detalhes da implementação da linguagem
no ambiente paravirtualizado, com considerações e resultados finais.
O capítulo 8 aborda a conclusão do trabalho e trabalhos futuros.
17
2 VIRTUALIZAÇÃO
Em meio às muitas tecnologias que surgiram nos últimos anos, a virtualização é
um conceito que está sendo cada vez mais utilizado na área de tecnologia da
informação. De acordo com a IBM (2005), a virtualização simplifica a infra-estrutura,
reduz a complexidade e os custos otimizando os recursos. Para qualquer área dentro de
uma empresa, a virtualização pode ser útil, pois muitos sistemas podem estar baseados e
implementados em sistemas virtualizados, aumentando a disponibilidade, resiliência e
facilitando a administração.
Sempre há prós e contras a respeito de qualquer conceito, inclusive a
virtualização. Neste capítulo serão apresentados os conceitos, os tipos de virtualização
mais conhecidos, os benefícios de se utilizar a tecnologia citada e a diversidade de
ferramentas existentes.
2.1 INTRODUÇÃO SOBRE VIRTUALIZAÇÃO
De acordo com Bernard Golden e Clark Scheffy (2008, p.06 e 07), hoje muitos
data centers possuem máquinas sendo utilizadas com apenas 10% a 15% da capacidade
total de processamento. Em outras palavras, 85% a 90% da capacidade das máquinas
não são utilizadas. Além disso, a necessidade de novas aplicações e sistemas faz com
que novos servidores e máquinas de todos os tipos sejam adquiridos e que os data
centers precisem de cada vez mais espaço para disposição de servidores.
Figura 1 - Várias máquinas virtuais em um único hardware
Fonte: VmWare (2008)
18
De maneira simples, a virtualização é uma técnica para se utilizar diversos
sistemas operacionais distintos, mas em um único hardware, conforme ilustra a Figura
1.
De acordo com Jones (2006), virtualizar significa pegar algo que está em uma
forma e fazê-la parecer de outra forma. Virtualizar um computador significa fazê-lo
parecer múltiplos computadores ou um computador completamente diferente.
Dependendo do ponto de vista, também pode significar fazer com que muitos
computadores pareçam um único computador. Isto pode ser chamado de Server
Agregation (agregação de servidores) ou Grid Computing (grid de computadores).
A virtualização emula componentes de hardware para o sistema operacional
através de técnicas, hardwares e softwares de virtualização. Essas técnicas são hoje
utilizadas tanto para desktops quanto para servidores.
O conceito de virtualização não é algo recente, mas após uma longa jornada
passou a evoluir de maneira considerável nos últimos anos. Surgiram então diversas
abordagens, mostrando varias vantagens e desvantagens dependendo da técnica a ser
utilizada.
[...] Uma máquina virtual não pode ser comprometida pela operação
de qualquer outra máquina virtual. Ela fornece um ambiente
computacional privado, seguro e confiável para seus usuários. [...]
Novas facilidades, como sistemas de banco de dados ou suporte a
dispositivos especializados podem ser adicionados sem modificação
ou corrompimento das atuais capacidades. [...] (CREASY, 1981,
p.487)
2.2 HISTÓRIA DA VIRTUALIZAÇÃO
De acordo com a IBM (2006), a virtualização não é um tópico novo, pois o
conceito de virtualização surgiu por volta do ano de 1960, quando a IBM, em conjunto
com o MIT (Massachusetts Institute of Technology), tratava de um projeto chamado
M44/44X. A meta era avaliar os conceitos de sistema de compartilhamento de tempo
(Compatible Time-Share System, como era chamado). A máquina principal era um IBM
704 (M44) e cada máquina virtual era uma imagem experimental da máquina principal
(44X). O espaço de endereçamento do 44X residia na hierarquia de memória do M44 e,
além disso, era utilizado um sistema de memória virtual e multiprogramação.
19
Este Mainframe executava duas máquinas virtuais, uma para executar programas
e outra para o sistema. O sistema operacional do Mainframe era chamado de Supervisor.
Alguns anos depois a IBM desenvolveu os computadores da família 360. Foi
lançado o Mainframe System/360. Nesse Mainframe o hardware era acessado pela
interface chamada VMM (Virtual Machine Monitor). O VMM permitia a execução das
máquinas virtuais onde cada máquina executava uma instância do sistema operacional
principal.
O VMM executava diretamente na camada de hardware, permitindo
múltiplas máquinas virtuais (VMs). Cada VM podia executar uma
instância do sistema operacional – nos dias mais antigos isto era o
CMS, ou Conversational Monitor System. A VM continuou a avançar,
e hoje podemos encontrá-la sendo executada no mainframe System z9.
Isto fornece compatibilidade antiga até mesmo com a linha
System/360. (JONES, 2006)
De acordo com Manfrin (2010), na época, os Mainframes eram máquinas X86
com um grande poder de processamento, mas que não eram completamente
aproveitadas, utilizando somente de 10 a 15% de sua capacidade, pois normalmente
eram implementadas para aplicações específicas, diminuindo os riscos de ficarem fora
de produção.
2.3 NECESSIDADE DA VIRTUALIZAÇÃO
De acordo com a VmWare (2010), a virtualização foi praticamente abandonada
durante os anos 80 e 90, quando aplicações cliente-servidor, servidores e desktops X86
começaram a ser distribuídos. A adoção de sistemas operacionais Linux e Windows
como sistemas para servidores começaram a ser o padrão da indústria. Com esse
crescimento de servidores e desktops X86, passou a surgir uma nova infra-estrutura de
TI e novos desafios operacionais. A VmWare, uma das empresas que fornecem
tecnologia de virtualização, informa que alguns desses desafios são:
- Baixa utilização de infraestrutura. De acordo com a IDC (International Data
Corporation), a distribuição de servidores x86 atinge uma média de utilização de
10% a 15% da capacidade total. As organizações geralmente executam uma
aplicação por servidor para evitar riscos de vulnerabilidade, ou seja, para que
problemas afetando uma aplicação, não afetem a disponibilidade de outra que
esteja no mesmo servidor;
20
- Aumento do custo da infraestrutura física. É necessário suprir os custos
operacionais do crescimento da infraestrutura. A maioria dos ambientes
computacionais precisa estar disponível em quase 100% do tempo, resultando
em consumo de energia, resfriamento, e custos que não variam;
- Aumento do custo de gerenciamento de TI. Devido aos ambientes
computacionais se tornarem mais complexos, os custos associados ao nível de
educação especializada e experiência requerida para o gerenciamento da
infraestrutura aumentam consideravelmente;
- Proteção insuficiente contra desastres e falhas. Organizações são afetadas
devido à inacessibilidade a aplicações críticas. Ameaças a segurança por meio de
ataques, desastres naturais e terrorismos aumentaram a importância do
planejamento continuo dos negócios, tanto para desktops como para servidores;
- Alta manutenção de desktops de usuários finais. Diversos desafios são
apresentados às empresas quando gerenciam e fornecem segurança para
desktops. Controlar e gerenciar um ambiente de desktop distribuído, com
diretivas de acesso e segurança sem impactar na habilidade do usuário de
trabalhar efetivamente, é complexo e caro.
De acordo com uma pesquisa realizada com empresas de IT (Information
Technology) e com LOB (Line Of Business – outras áreas de negócio) pela IDC (2008),
a tecnologia que tem mais impacto na transformação dos processos de negócio na área
de TI, conforme Gráfico 1, é a virtualização.
Figura 2 – Tecnologia com mais impacto na transformação dos
processos de negócio
Fonte: IDC (2008)
21
Devido a essas e outras necessidades, as técnicas de virtualização foram
surgindo e evoluindo em grande escala. Segundo a Gartner (2008), é esperado que o
número de computadores virtualizados cresça de menos de 5 milhões em 2007 para 660
milhões em 2011, e Pettey (2008) diz que a virtualização é o problema que terá maior
impacto até 2012, modificando infraestruturas e operações e modificando também a
maneira de comprar e de gerenciar.
2.4 EMULAÇÃO DE HARDWARE
De acordo com Jones (2007), a emulação de hardware nada mais é do que a
virtualização do hardware. Provavelmente quando se fala em virtualização, a emulação
de hardware é indicada como a mais complexa. Através das camadas virtuais de
hardware é possível criar diferentes ambientes utilizando a mesma máquina física,
conforme ilustra a Figura 2.
Com a emulação de hardware alguns benefícios são apresentados, como por
exemplo: É possível simular diversos processadores, mesmo que o hardware real possua
apenas um processador físico. Pode-se também executar diversas máquinas virtuais,
cada uma simulando um processador diferente.
Uma das utilizações mais importantes da emulação de hardware é no
desenvolvimento de firmware e hardware. Ao invés de esperar até que
o hardware esteja disponível, os desenvolvedores de firmware podem
utilizar o hardware VM alvo para validar muitos aspectos de seus
códigos atuais em simulação. (JONES, 2006)
Este tipo de virtualização precisa de um software que entenda as instruções da
arquitetura que se deseja emular. Esta é a técnica utilizada pelos desenvolvedores de
emuladores de vídeo-game, na qual o software irá converter as instruções recebidas da
Figura 3 - Emulação de hardware
Fonte: IBM (2006)
22
arquitetura em que se está emulando, para que o sistema operacional convidado
(também conhecido por GuestOS) possa entender as instruções.
2.5 VIRTUALIZAÇÃO COMPLETA
De acordo com a VmWare (2007) a virtualização completa é uma técnica
utilizada para fornecer um ambiente de máquina virtual, que simula de maneira
completa o hardware como réplica do hardware real.
Segundo Menascé (2005), o sistema operacional executado através de
virtualização completa, que pode ser chamado de sistema operacional convidado, não
necessita de modificações, visto que é executado através do VMM, o monitor de
máquina virtual. O VMM é uma camada de software mais próxima ao hardware. Esta
camada, que está entre o hardware e o sistema operacional convidado concede uma
abstração da máquina virtual, conforme ilustra a Figura 3. O VMM suporta um número
muito grande de dispositivos. Por isso a Virtualização completa utiliza dispositivos
genéricos para fazer com que a máquina virtual execute. O fato destes dispositivos não
serem específicos faz com que o desempenho da máquina virtual não seja atingido em
sua totalidade. A máquina virtual acredita ser executada em um hardware real. Logo, o
VMM precisa testar as instruções passadas pela máquina virtual para que em seguida as
execute diretamente no hardware. Isso também acontece quando o hardware fornece
alguma instrução, pois o VMM primeiro interpreta e testa a instrução antes de passar
para a máquina virtual. Além dos aspectos citados, o VMM ainda precisa controlar
alguns aspectos relacionados à disputa de recursos, o que causa certa queda de
desempenho, visto que os sistemas operacionais foram desenvolvidos para não
coexistirem com outros tentando utilizar os mesmos recursos.
Figura 4 - Virtualização completa
IBM (2006)
23
2.6 PARAVIRTUALIZAÇÃO
Segundo Origuela (2006), a técnica de paravirtualização utiliza um conceito
parecido com o da virtualização completa. Nesta, o sistema operacional convidado é
alterado para interagir com o VMM, para então decidir quais instruções devem ser
interpretadas nele ou diretamente no hardware. Os drivers de dispositivos de sistemas
paravirtualizados entendem que estão sendo executados como um sistema virtualizado,
por isso, durante as requisições, os drivers dos dispositivos da máquina convidada
conversam com os drivers reais do sistema operacional principal.
De acordo com Jones (2007) a técnica de paravirtualização não simula recursos
de hardware, mas ao invés disso oferece uma interface de programação de aplicação
(API) para as máquinas virtuais hospedadas, e para isso, o sistema operacional precisará
ter sido modificado para suportar tal interface. A paravirtualização é suportada em
sistemas que foram modificados para entender que certas requisições, que seriam feitas
diretamente ao hardware físico, deverão na verdade ser realizadas primeiramente ao
VMM ou Hypervisor, como é chamado muitas vezes, para que o VMM se comunique
com o host e aja diretamente no hardware, para então devolver as respostas das
requisições.
A paravirtualização utiliza o conceito de domínios. Existe um domínio chamado
domínio zero, onde reside o sistema operacional que tem acesso direto ao hardware.
Este domínio precisa possuir um sistema que foi modificado para suportar
paravirtualização como domínio zero, e é através dele que é realizado o gerenciamento
das máquinas virtuais.
Figura 5 - Paravirtualização
Fonte: Uberhip (2007)
24
Além do domínio zero, existe o domínioU, onde residem as máquinas virtuais.
Cada máquina virtual que reside em um domínioU também precisa ter sido modificada.
Cada domínioU executa uma instância completa de um sistema operacional.
Para utilizar a paravirtualização, não é necessária a utilização de hardware com
suporte à virtualização, pois os sistemas operacionais já são modificados para suportar
esta técnica, conforme ilustra a Figura 4.
De acordo com a IBM (2006), a paravirtualização oferece um desempenho
muito próximo ao de sistemas não virtualizados.
2.7 VIRTUALIZAÇÃO DE SISTEMA OPERACIONAL
De acordo com o arquiteto da Microsoft Chantry (2009), a técnica da
Virtualização de sistema operacional utiliza um sistema operacional como sistema base.
Os sistemas convidados compartilham os mesmos recursos e drivers do sistema
operacional base, mesmo que pareçam computadores totalmente separados, conforme
ilustra a Figura 5. Cada sistema operacional convidado terá o seu próprio sistema de
arquivos, endereço IP, configurações de servidor e executarão aplicativos totalmente
diferentes.
Figura 6 - Virtualização de sistema operacional
Fonte: Chantry (2009)
2.8 HARDWARE COM SUPORTE À VIRTUALIZAÇÃO
Diversas técnicas de virtualização existem hoje e, além disso, muitos softwares
são construídos com base em uma técnica. Além da construção de softwares com
suporte à virtualização, existem hardwares que são produzidos para auxiliar tais
softwares na execução de tarefas essenciais, de acordo com a Intel (2010).
25
A Intel lançou a tecnologia Intel VT (Intel Virtualization Techonlogy) que está
presente em diversos processadores para auxiliar softwares de virtualização e, de acordo
com a Intel (2010), proporcionar a utilização máxima do sistema por meio de
consolidação de ambientes em um único servidor ou PC.
Além da Intel VT a empresa AMD possui a tecnologia chamada AMD-V. De
acordo com a AMD (2009) a tecnologia foi desenvolvida para aumentar drasticamente o
desempenho da aplicação virtualizada, possibilitando também a alternância mais rápida
entre máquinas virtuais, para que mais máquinas virtuais possam ser hospedadas por
servidor, maximizando os benefícios da virtualização.
Os hardwares com suporte à virtualização auxiliam os softwares de virtualização
para que os sistemas operacionais não precisem ser modificados para poderem ter um
melhor desempenho durante sua execução.
Alguns softwares de virtualização funcionam com um bom desempenho apenas
quando o hardware possui suporte à virtualização. Entretanto, há softwares que não
necessitam de hardware com suporte à virtualização, mas que conseguem um ótimo
desempenho durante a execução de máquinas virtuais devido ao fato de os sistemas
operacionais terem sido modificados para tal.
26
3 FERRAMENTAS PARA VIRTUALIZAÇÃO
Diferentes ferramentas estão disponíveis hoje e cada uma utiliza uma técnica de
virtualização diferente. Na Tabela 1, pode-se visualizar as principais ferramentas
disponíveis e os tipos de virtualização que utilizam. Cada ferramenta possui seus pontos
fortes e fracos, incluindo ferramentas livres e pagas.
Tabela 1 – Ferramentas de virtualização
Fonte - O autor
Ferramenta Tipo
Bochs Emulação
QEMU Emulação
VMWare Virtualização completa
Linux KVM Virtualização completa
Hyper-V Virtualização completa – Paravirtualização
Xen Paravirtualização – Virtualização completa
UML Paravirtualização
Linux V-server Virtualização de sistema operacional
Open VZ Virtualização de sistema operacional
3.1 BOCHS
A ferramenta Bochs (que se pronuncia Box) é um emulador de software que não
possui interface gráfica. A ferramenta é livre e emula computadores Intel x86. De
acordo com a Bochs (2009), o Bochs emula apenas máquinas i386, i486, Pentium,
Pentium Pro da Intel e CPUs AMD64, além de periféricos comuns como discos,
memória, monitor e dispositivos de rede. A ferramenta foi desenvolvida em C++ e seu
código pode ser compilado em basicamente qualquer plataforma, seja em Windows,
MacOS X ou em várias versões de Unix. O software foi escrito por Kevin Lawton que
ainda o mantém.
O Bochs foi criado para emular sistemas operacionais Linux, DOS e Windows
95/98/XP/2000/NT.
O fato de ser compatível com diversas plataformas é um ponto forte e ao mesmo
tempo fraco em relação a outras máquinas virtuais, visto que os equipamentos como
BIOS, placas de vídeo, som e basicamente todos os componentes são emulados através
27
do software, o que faz com que a portabilidade seja maior, mas a velocidade passa a ser
menor.
3.2 QEMU
De acordo com Bellard (2005), o próprio desenvolvedor do Qemu, o software
suporta dois modos operacionais: a emulação em modo de usuário e a emulação em
modo de sistema. A emulação em modo de usuário permite que um processo construído
para executar em certa CPU possa ser executado em outra, utilizando um conversor
dinâmico como técnica para emulação, para que as partes do código sejam convertidas
de maneira que o processador execute o conjunto de instruções. A emulação em modo
de sistema permite a emulação de um sistema integral, incluindo processador e
periféricos de diferentes tipos.
[...] o QEMU como um emulador do sistema PC fornece uma extensa
variedade de periféricos.[...] Um emulador Vídeo Graphics Array
(VGA) de hardware, mouse e teclado PS/2, disco rígido e interface de
CD-ROM do Ambiente de Desenvolvimento embarcado (IDE) e
emulação de disco flexível. [...] Inclui a emulação para um adaptador
de rede NE2000, portas seriais, numerosas placas de som e um
controlador Universal Serial Bus (USB).[...] (Jones, 2007)
Bellard (2005) também informa que para otimizar a emulação alguns módulos,
aceleradores Qemu podem ser instalados fazendo com que o desempenho quase nativo
possa ser obtido, permitindo que o código emulado seja executado diretamente na CPU
real (do host).
A princípio, o Qemu foi desenvolvido para executar um sistema operacional em
outro, como um Windows em um Linux ou um Linux em um Windows. Ele pode
executar em diversos sistemas operacionais como Linux, Windows e MacOs X.
O ponto forte do Qemu é o fato de possuir um conversor dinâmico, rápido e
portátil, que traduz as instruções para a CPU convidada vindas da CPU host, fornecendo
assim a emulação. O conversor pode fazer cache de trechos de código para minimizar a
sobrecarga, tornando-o mais rápido.
3.3 VMWARE
A empresa VmWare (2010) fornece uma variedade de ferramentas para
virtualização, desde softwares gratuitos para virtualização de desktops e servidores, até
28
plataformas abrangentes de nível empresarial para otimização de data centers e da
infraestrutura de TI. As ferramentas gratuitas são limitadas, enquanto as pagas fornecem
recursos bem mais avançados.
Diversos produtos são disponibilizados pela VmWare (2010), como por exemplo
o VmWare Workstation, VmWare Server, VmWare Player, que são ferramentas de
virtualização que executam em um sistema hospedeiro. Existe outra plataforma
chamada VmWare ESX, ilustrada na Figura 6, que por si mesma é um sistema
operacional hospedeiro baseado em Linux.
Figura 7 – VmWare ESX
Fonte: VmWare (2010)
Pelo fato de utilizar virtualização completa, todos os componentes de hardware
são virtualizados, e o suporte para todos os dispositivos são fornecidos pelo próprio
sistema operacional hospedeiro. O VmWare utiliza drivers genéricos para os
dispositivos, chamado de VMDriver. Pelo fato de utilizar dispositivos genéricos, o
desempenho das máquinas diminui.
De acordo com a VmWare (2010), o desempenho do VmWare ESX chega a ser
melhor do que as ferramentas que precisam de um sistema hospedeiro, mas a
portabilidade diminui devido a limitações do próprio sistema. O VmWare possui
ferramentas com interface gráfica que facilitam a administração das máquinas virtuais
existentes. O VmWare faz uso do VMM, que intercepta e testa as instruções passadas
pela máquina virtual para poder então executá-las diretamente no hardware. O mesmo
acontece quando o hardware fornece alguma instrução, pois o VMM a interpreta e passa
para a máquina virtual. Além disso, os recursos da máquina hospedeira são disputados
29
pelas máquinas virtuais, e por isso o VMM também realiza o controle desses recursos, o
que causa mais queda no desempenho.
3.4 LINUX KVM
De acordo com os desenvolvedores do KVM (2010), KVM significa Kernel-
based Virtual Machine. O Linux KVM é um framework de virtualização completa que
utiliza as tecnologias de virtualização Intel-VT e AMD-V, que estão nos processadores
mais recentes. O KVM é uma ferramenta livre e está presente no Kernel Linux 2.6.20, e
é possível executar qualquer sistema operacional sem que nenhuma modificação seja
realizada, desde que haja tecnologia de virtualização embutida no processador. Cada
máquina virtual é tratada como um processo Linux, por isso pode-se manipular as
máquinas com comandos de manipulação de processos.
3.5 HYPER-V
Hyper-V é a solução de Virtualização completa Microsoft parecido com as
ferramentas VmWare. Além disso, de acordo com a Microsoft (2010), a ferramenta
suporta paravirtualização para sistemas operacionais que são modificados para tal. A
Microsoft possui o Hyper-V Standalone como sendo o próprio sistema hospedeiro além
de possuir a opção de ser executado em um host Windows Server 2008. Quando
adquirido o Windows Server 2008 R2, o Hyper-V faz parte do sistema, não sendo
necessário adquirir licenças. Para a utilização de alguns recursos, o Hyper-V necessita
do System Center Virtual Machine Manager, que necessita de licenças para funcionar.
A Microsoft (2010) informa que para o funcionamento do Hyper-V é necessário
possuir as tecnologias de aceleração de virtualização nos processadores como Intel VT
ou AMD-V. O Hyper-V é uma ferramenta que ainda está em aperfeiçoamento, mas
possui alguns benefícios por ser desenvolvido pelo próprio fabricante do Windows, o
que traz algumas compatibilidades e facilidades na administração.
3.6 XEN
O Xen (2010) é uma ferramenta de paravirtualização que também suporta
virtualização completa quando o hardware possui suporte a tecnologia Intel VT ou
AMD-V, que foi desenvolvido em um projeto na Universidade de Cambridge, que mais
tarde tornou-se a empresa XenSource Inc, e então foi adquirida pela Citrix System em
outubro de 2007. O Xen possui um desempenho melhor do que os produtos que utilizam
virtualização completa quando o hardware da máquina física não possui suporte a
30
virtualização. Na virtualização completa, algumas tarefas que precisam ser executadas
pelas máquinas virtuais não podem ser executadas diretamente no processador, pois são
tratadas como um processo na camada de aplicação da máquina hospedeira. Com isso, o
VMM intercepta as tarefas, e as executa. Isto causa certa perda de desempenho em
hardwares sem suporte à virtualização. Já na paravirtualização, os sistemas operacionais
a serem executados, precisam ser modificados para que estas tarefas específicas, que
precisariam ser executadas na CPU, possam ser diretamente executadas no VMM, sem
haver a tentativa de acesso direto a CPU e sem que o VMM as intercepte, trazendo
ganho de desempenho.
Uma grande vantagem do Xen é que ele pode executar máquinas virtuais em
hardwares que não possuem suporte à virtualização, com um desempenho muito
próximo ao da máquina nativa. Apesar disso, os sistemas operacionais precisam ser
modificados para funcionarem.
Hoje já existem diversos sistemas com suporte ao Xen, como o Linux, FreeBSD
e Windows, mas alguns necessitam de tecnologia de hardware Intel VT ou AMD-V para
utilizar a virtualização completa, e outros já possuem o código modificado para utilizar
paravirtualização.
Nas Tabelas 2 e 3 são citados os sistemas operacionais que suportam o Xen
como servidor e como máquina convidada.
Tabela 2 – Suporte Xen 3.0
Fonte: O autor
OS Executar como
Dom0 (host)
Executar como domU
(convidado)
Linux 2.6 Sim Sim
NetBSD 3.1 Não Sim
NetBSD 4.0_Beta2 e atual Sim Sim
FreeBSD 5.3 Não Sim
FreeBSD 7 Não Sim
Solaris 10 Não Sim
Sistemas Operacionais não
Modificados
Não Sim, somente quando o
hardware possui suporte Intel
VT ou AMD-V
31
32
Tabela 3 – Suporte Xen 2.0
Fonte: O autor
Sistema operacional Executar como
Dom0 (host)
Executar como
domU (convidado)
Linux 2.4 Sim Sim
Linux 2.6 Sim Sim
NetBSD 2.0 Não Sim
NetBSD 3.0 Sim Sim
Plan 9 Não Sim
FreeBSD 5 Não Sim
De acordo com a Xen (2008), cada máquina virtual é chamada de domínio.
Existem dois tipos de domínio: o domínio 0 (chamado de domain0 ou dom0), que é o
domínio de controle, e o domínio U (chamado domainU ou domU), que é o domínio
sem privilégios, ou seja, o sistema operacional convidado. Cada domínio executa uma
instância completa do sistema operacional.
Figura 8 – Componentes do Xen
Fonte: Carissimi (2008)
33
Para que o Xen ofereça suporte tanto à virtualização completa quanto à
paravirtualização, é utilizado o conceito dos domínios explicado anteriormente, com
algumas modificações. O Xen reconhece os domínios U-PV, como domínios
paravirtualizados e U-HVM (hosted virtual machines) como domínios virtualizados. Os
domínios U-PV são os domínios que possuem os sistemas operacionais modificados,
que sabem que existem outras máquinas virtuais e possuem drivers específicos para
acesso à rede e disco e, além disso, sabem como interagir com o domínio 0. Os
domínios U-HVM não são modificados, ou seja, não sabem que existem outras
máquinas virtuais e por isso não possuem drivers específicos para o acesso a recursos,
necessitando do hardware com suporte à virtualização para que o desempenho não caia,
conforme ilustra a Figura 7.
De acordo com a Xen (2008), para que o domínio U-HVM funcione, ele faz o
uso do Qemu (o emulador de software), e os recursos de hardware que são disponíveis
para o domínio são os mesmos oferecidos pelo Qemu.
3.7 UML
UML (User mode Linux) permite que um sistema operacional Linux execute
outro sistema operacional Linux como convidado através da paravirtualização. De
acordo com Dike (2010), cada sistema operacional Linux convidado existe como um
processo no host Linux. Isto permite que vários Kernels de versões diferentes possam
ser executados em uma única versão de Kernel Linux, conforme ilustra a Figura 8.
Figura 9 – User mode Linux
Fonte: IBM (2006)
Um dos grandes benefícios e foco do UML é poder realizar testes em versões de
Kernels Linux diferentes sem prejudicar o host Linux principal. O UML também
fornece mais recursos de hardware e software do que os da máquina física (host).
34
Jones (2007) explica que os Kernels convidados executam no espaço de
aplicação, e para funcionarem precisam ter sido compilados para tal, enquanto o Kernel
Host reside diretamente no hardware.
35
4 ASTERISK
O Asterisk é um software livre que implementa recursos de PBX completo e
muitas outras funções através da tecnologia de VoIP. Mark Spencer da Digium Inc. foi
quem iniciou o projeto por volta do ano de 1999. Inicialmente o Asterisk foi
desenvolvido para implementar apenas recursos em software como um PBX de código
aberto, mas de acordo com Davenport (2010), hoje o Asterisk implementa não apenas
recursos de sistemas PBX, mas também gateways VoIP, sistemas de Call Center, pontes
de conferência, servidores voicemail e todos os tipos de aplicativos que envolvam
comunicação em tempo real.
O sistema roda em servidores Linux e faz VoIP através de três diferentes
protocolos. De acordo com a Asterisk Brasil (2010), o Asterisk pode se integrar a
praticamente todos os padrões de telefonia utilizando hardware de baixo custo. Ele é um
servidor de comunicação que detém todos os níveis baixos de detalhes para envio e
recebimento de dados utilizando alguns diferentes tipos de protocolos. Os protocolos
utilizados pelo Asterisk são protocolos abertos como o SIP, MGCP e IAX, os quais
realizam a sinalização das chamadas telefônicas na rede IP.
Após a instalação do Asterisk, um servidor de comunicação passa a existir, mas
para que ele realmente se comunique, é preciso criar aplicativos de comunicação
realizando e alterando configurações, que o fará funcionar da maneira planejada. Estes
aplicativos de comunicação são construídos através de scripts, arquivos de
configuração, gravações de áudio, banco de dados, serviços web, etc. Para que um
aplicativo de comunicação funcione, é preciso que o servidor de comunicação esteja
conectado a serviços de comunicação como VoIP ou PSTN. Para que as pessoas
acessem o sistema de comunicação, é preciso ter números de telefones ou URLs VoIP
que enviem chamadas ao servidor.
4.1 SIP
De acordo com a IETF (2010), o SIP é um protocolo IETF (RFC 2543, 1999) de
aplicação parecido com o HTTP ou SMTP, que segue o modelo requisição-resposta
para iniciar sessões de comunicação VoIP e outras sessões de texto e multimídia, como
mensagens instantâneas, vídeo, jogos online e outros serviços. Para comunicação, ele
utiliza a porta 5060 tanto UDP como TCP. Alguns recursos que o protocolo oferece na
parte de telefonia são: transferências de chamada, conferências telefônicas e chamadas
em espera. Por ser um protocolo flexível, é possível adicionar mais recursos ao SIP.
36
4.2 MGCP
De acordo com a Arango (1999), o MGCP também é um protocolo do grupo
IETF que integra a arquitetura SS7 em redes VoIP. A arquitetura SS7 é uma rede de
pacotes que se agrega à rede de telecomunicação, adicionando novas funcionalidades e
serviços que estão presentes em centrais telefônicas. O SS7 é quem possibilita a
comunicação de centrais telefônicas de maneira confiável e rápida. O MGCP possuiu
um agente de chamada, um MG (Media Gateway), que é o responsável pela conversão
de sinais entre circuitos, e pelo menos um SG (Signaling Gateway) conectado a um
PSTN.
4.3 IAX
De acordo com Guy (2009), o IAX é um protocolo desenvolvido para
estabelecer conexão entre servidores Asterisk, que também já está presente em telefones
VoIP. Ele foi desenvolvido pela Digium Inc., que é a empresa desenvolvedora do
Asterisk. O IAX é parecido com o protocolo SIP citado anteriormente, com a diferença
de que faz uso de uma única porta UDP de número 4569. O IAX já está na versão 2,
mais conhecido por IAX2. Um dos grandes benefícios do IAX é que ele suporta
entroncamento de chamadas, ou seja, é possível unir chamadas que se entroncaram em
um único conjunto de pacotes e entregar informações para mais de uma chamada ao
mesmo tempo.
37
5. LINGUAGENS DE PROGRAMAÇÃO
Linguagem de programação é um conjunto de regras que são utilizadas para
definir um programa para ser utilizado no computador. Existem alguns tipos de
linguagens: alto nível, nível intermediário ou baixo nível.
De acordo com Carter (2002, p.46), a linguagem de baixo nível é uma
linguagem em que o código é executado diretamente pelo processador. É formada por
zeros (0) e uns (1). Por isso também é chamada de linguagem binária ou de máquina. A
linguagem de nível intermediário é uma linguagem em que os códigos fonte são
chamados de mnemônicos (assembly) onde cada instrução de máquina tem uma
representação em texto (como ADD, SUB, ou LOAD). A linguagem de nível
intermediário precisa ser transformada em linguagem de baixo nível, por isso era
necessário um montador que realizasse a conversão.
Tabela 4 – Tipos de linguagens
Fonte: O autor
Linguagem Compilada/Interpretada
ADA Compilada
BASIC Interpretada
C Compilada
C++ Compilada
Cobol Compilada
Fortran Compilada
Java Intermediária (híbrida)
MATLAB Interpretada (híbrida)
LISP Intermediária (híbrida)
Pascal Compilada
PHP Interpretada
Prolog Interpretada
Prolog Interpretada
Perl Interpretada
Lua Interpretada
38
A linguagem de alto nível é uma linguagem que é mais facilmente entendida
pelo ser humano. Antigamente a programação era bem tediosa, pois para executar
operações um pouco mais complexas eram necessárias muitas instruções e, além disso,
as instruções disponíveis eram diferentes de máquina para máquina. Com isso surgiram
as primeiras linguagens de alto nível como Pascal, COBOL e C. Através da linguagem
de alto nível é possível desenvolver programas em muito menos instruções, ou seja, seu
desenvolvimento é muito mais rápido do que era antigamente. Para que a linguagem de
alto nível seja entendida pela máquina é preciso de alguém que a traduza. Existem
algumas maneiras para realizar a tradução, seja através de um compilador ou
interpretador. Na tabela 4, estão listadas algumas linguagens importantes e seus
respectivos tipos.
5.1 LINGUAGENS INTERPRETADAS
Linguagem interpretada é uma linguagem de programação que necessita de um
interpretador para ser executada. O código-fonte de uma linguagem interpretada só será
entendido pela máquina se houver o interpretador para traduzir a respectiva linguagem.
De acordo com Louden (2004, p.04), um interpretador é um tradutor de
linguagens, assim como o compilador. A diferença é que o interpretador executa o
programa-fonte de imediato, traduzindo as instruções de programação conforme são
lidas pelo programa, em vez de gerar um código-objeto que seja executado após o
término da tradução.
Figura 10 - Linguagem interpretada
Fonte: Caldas (Slide 14)
De acordo com Sebesta (2002, p. 154), algumas linguagens são tipicamente
interpretadas, outras utilizam os dois métodos (compilação e interpretação) para serem
executadas. Um interpretador compartilha muitas de suas operações com os
compiladores, podendo existir compiladores híbridos que ficam entre os interpretadores
e compiladores. Se uma linguagem for compilada e o código gerado não for entendido
39
pelo sistema operacional e processador, necessitando de que algum mecanismo a
interprete, esta linguagem também será uma linguagem interpretada.
5.1.1 LINGUAGEM DE EXTENSÃO OU SCRIPT
Linguagem de extensão também pode ser chamada de linguagem de script. Essas
linguagens normalmente controlam programas, pois são executadas dentro deles. De
acordo com a Stanford University (2004), as linguagens de extensão são muito
utilizadas em sistemas operacionais e também em muitos jogos. O Linux é um sistema
operacional que utiliza bastante a linguagem de extensão para controlar aplicativos e
rotinas do próprio sistema operacional. O Windows também utiliza linguagem de
extensão. Um exemplo disso são os scripts VBS. Alguns jogos utilizam a linguagem de
extensão para poder controlar ações de personagens.
Pode-se dizer que toda linguagem de extensão é uma linguagem interpretada,
mas que nem toda linguagem interpretada é uma linguagem de extensão.
As linguagens de extensão são classificadas segundo sua complexidade:
- Linguagem de Macro:
São utilizadas para tarefas de automação com abrangência mais limitada.
- Linguagens Embutidas:
Permitem o acesso programável aos serviços da aplicação hospedeira (ou
principal). São linguagens mais completas e mais complexas que a anterior.
Figueiredo (2002) informa que a adoção de uma linguagem de extensão é um
poderoso recurso no desenvolvimento de softwares, pois permite que muitos aspectos
da aplicação hospedeira sejam controlados externamente. Esse controle consiste na
edição de arquivos textos facilmente modificados pelo desenvolvedor sem a necessidade
de recompilar a aplicação, tornando o desenvolvimento mais rápido e muito mais
flexível.
Uma linguagem de extensão deve ter como foco a produtividade do
programador. Segundo Proebsting (2002), um dos problemas mais sérios no
desenvolvimento de uma linguagem de programação é em como melhorar a
produtividade do programador. Os hardwares atualmente possuem um poder de
processamento suficientemente grande para não precisar de otimização massiva da
linguagem internamente.
40
5.2 LINGUAGENS COMPILADAS
Linguagem compilada é uma linguagem onde o código fonte é executado
diretamente pelo sistema operacional ou pelo processador. O código é traduzido para
executar um conjunto de regras ou instruções, e esse processo chama-se compilação.
Para isso, é utilizado um software próprio, chamado compilador, que efetua a tradução
para linguagem de baixo nível, como linguagem de montagem ou código de máquina.
De acordo com Louden (2004, p. 13), a geração do código é muito complexa,
pois depende das informações da estrutura do ambiente de execução, através de
tentativas de otimizar ou aperfeiçoar a velocidade ou tamanho do código fonte. A
linguagem compilada elimina essa fase em vários passos, utilizando estruturas de dados
intermediários.
Após a compilação, cria-se um programa executável, armazenando as
informações e não é necessário a recompilação.
Figura 11 - Linguagem compilada
Fonte: Caldas (Slide 14)
A vantagem é que o usuário nunca terá acesso ao código fonte, evitando assim a
alteração e danificação do programa.
41
6 METODOLOGIA
Neste capítulo serão apresentados a metodologia adotada e informações
necessárias para atingir o objetivo proposto no trabalho, além de justificar a escolha das
tecnologias utilizadas.
Esta parte do trabalho foi dividida em etapas que ajudarão a construir um
ambiente com suporte à paravirtualização, instalar e configurar o Asterisk em máquina
virtual, desenvolver uma linguagem que possa ser interpretada pelo Asterisk, utilizar a
API do Asterisk para que entenda a linguagem criada, e a execução de testes com VoIP
utilizando o ambiente e linguagem criados.
As etapas necessárias estão divididas da seguinte forma:
1. Ambiente virtualizado:
- Escolha da tecnologia de virtualização que será utilizada;
- Criação e configuração do ambiente virtualizado;
- Instalação e configuração do Asterisk.
2. Linguagem interpretada:
- Desenvolvimento da linguagem interpretada;
- Fazer a integração da linguagem com o Asterisk através da API do
próprio Asterisk.
3. Testes finais:
- Realizar testes com VoIP utilizando a linguagem interpretada no
Asterisk paravirtualizado.
6.1 VIRTUALIZAÇÃO
A paravirtualização foi escolhida como técnica a ser utilizada para a
implementação do ambiente devido aos benefícios que ela apresenta. Como principais
benefícios pode-se citar que a paravirtualização pode ser implementada em qualquer
máquina da plataforma x86 sem necessitar de hardware com suporte à virtualização
(como Intel-VT ou AMD-V), por isso mais tipos de máquinas, inclusive máquinas mais
antigas, poderão ser utilizadas para a aplicação da técnica.
A ferramenta a ser utilizada para aplicação da técnica de paravirtualização será o
Xen com o sistema operacional Linux distribuição Open Suse, pois apresenta algumas
características que facilitarão a criação do ambiente como: um ótimo desempenho
mesmo utilizando máquinas sem hardware com suporte à virtualização e máquinas de
hardware comuns, software de código aberto, o que facilita ainda mais o acesso ao
42
software, além disso, já existem diversos sistemas operacionais com suporte a
paravirtualização e ao Xen.
O Xen será instalado e configurado no sistema operacional Linux Open Suse
como domínio 0. Uma máquina virtual será criada dentro do Xen. A máquina virtual
também possuirá o sistema operacional Linux Open Suse. Nesta nova máquina virtual
será instalado o software Asterisk em preparação para os próximos passos.
6.2 LINGUAGEM INTERPRETADA
O desenvolvimento do Interpretador, aqui chamado de dfn, consistirá em uma
linguagem feita em “C” para aplicações em “C/C++” que funcionará como extensão da
aplicação hospedeira que no caso será o Asterisk. Essa abordagem permite que a
aplicação seja expandida sem a necessidade de alteração de linha de código. Toda a
nova lógica, portanto, será implementada na linguagem aqui proposta.
A integração entre o interpretador e o Asterisk ocorrerá mediante o uso de
funções específicas, previamente definidas, conforme o documento "Asterisk Coding
Guideline" disponível no site do fabricante Asterisk (2010).
6.3 TESTES FINAIS
Após a criação do ambiente paravirtualizado, o desenvolvimento da linguagem
interpretada e configuração do Asterisk para entender a linguagem, será necessário
juntar os dois primeiros passos citados na introdução do capítulo 6 e realizar testes no
ambiente criado utilizando a linguagem desenvolvida. Estes testes envolverão o
desenvolvimento de um código utilizando a linguagem criada que substituirá arquivos
de configuração do Asterisk. Estes arquivos de configuração contêm instruções sobre
tomada de decisão relacionados ao VoIP. Em vez de o Asterisk ler o arquivo de
configuração padrão (extensions.conf), ele lerá o arquivo .dfn que será o motor da
linguagem aqui proposta. Para isso o Asterisk precisará entender a linguagem, ou seja,
interpretá-la. O Asterisk já deverá ter sido configurado para interpretá-la de acordo com
o que foi mencionado no item 6.2.
Ao final deste trabalho se chegará ao resultado da viabilidade do uso ou
desenvolvimento de uma linguagem interpretada (extensível) para permitir maior
flexibilidade na parametrização de aplicativos que necessitem do uso de configuração
para o seu funcionamento e de que a paravirtualização garante um SLA elevado uma
vez que na indisponibilidade de um hardware, outro poderá assumir como hospedeiro
43
mantendo o funcionamento dos serviços sem a necessidade de reinstalação de uma nova
máquina.
44
7 DESENVOLVIMENTO
A partir deste capítulo será abordada toda a estrutura de criação do ambiente
paravirtualizado, assim como os detalhes do desenvolvimento da linguagem
interpretada para sistema multi-plataforma. Para isso, foram necessários o estudo de
tecnologias necessárias para implementação do Asterisk, para a criação de uma
linguagem interpretada e de um ambiente virtualizado estável.
7.1 CONFIGURAÇÃO DO AMBIENTE
Para a implementação do Xen e Asterisk em preparação para os testes com a
linguagem criada será utilizada uma máquina Intel QuadCore Q9400 2.66GHz, 4GB de
memória RAM, 2 HDs de 1TB em RAID-1, com sistema operacional Linux distribuição
Open Suse 11.3.
7.2 DETALHES DE IMPLEMENTAÇÃO DA PARAVIRTUALIZAÇÃO
Para implementação das máquinas virtuais foi criada uma máquina real com o
sistema operacional Linux distribuição Open Suse 11.3 Português e interface KDE. Este
sistema é o sistema que chamamos de domínio 0 (domain0 ou dom0), que é o domínio
de controle, conforme explicado no item 3.6. É o domínio que possui o sistema Xen
para o controle e alocação das máquinas virtuais.
O OpenSuse 11.3 possui o Xen pré-instalado em um pacote que contém o Xen
Hypervisor. Para instalar o Xen Virtualization é preciso selecionar no menu de seleção
de Software e tarefas de sistema a opção Servidor hospedeiro de máquina virtual Xen,
conforme mostra a figura 11.
Figura 12 – Instalação Xen
Fonte: O autor
O particionamento foi dividido da seguinte forma:
-Volume de Swap /dev/sda1
- Volume Raíz /dev/sda2 com ext4
- Volume /dev/sda3 para /home com ext4
45
Para instalar o Hypervisor e Ferramentas foi necessário selecionar a opção
“instalar o Hypervisor e suas ferramentas” após a instalação do sistema operacional
conforme Figura 12.
Figura 13 – Instalando o Hypervisor e Ferramentas 1
Fonte: O autor
Ao instalar o Hypervisor e suas ferramentas é retornada a mensagem informando que o
servidor VM (domínio 0) foi configurado com sucesso e que estará pronto para a criação de
máquinas virtuais. Domínio 0 configurado e pronto para iniciar (ver figura 13):
Figura 14 – Domínio 0 configurado
Fonte: O autor
Após a instalação foi realizada a criação da máquina virtual no domínio U-PV,
que possui o sistema operacional modificado para executar a paravirtualização.
46
Abaixo está o exemplo do arquivo de configuração utilizado e modificado para a
manipulação da máquina virtual chamado vm_xen_tcc.conf localizado em
/images/config/:
#
# Arquivo de configuração da máquina virtual a ser usada no trabalho
#
kernel = "/images/TCC/boot/vmlinuz-xen"
ramdisk = "/images/TCC/boot/initrd-xen"
builder='linux'
memory = 512
name = "TCC_VM_DFN"
#uuid = "06ed00fe-1162-4fc4-b5d8-11993ee4a8b9"
# Number of Virtual CPUS to use, default is 1
vcpus = 1
vif = [ 'mac=00:16:3e:00:00:11, bridge=br0' ]
disk = [ 'file:/images/TCC/vdisks/sda_vdisk_12GB.img,xvda,w',
'file:/images/TCC/vdisks/sdb_vdisk_16GB.img,xvdb,w' ]
root = "/dev/xvda2"
vfb = [ 'vnc=1,vnclisten=0.0.0.0,vncunused=1,vncpasswd=reurbanisatus' ]
# Set root device.
#root = "/dev/hda1"
# Extra arguments to pass to the kernel.
extra = "xencons=xvc console=xvc0 video=tty"
#on_poweroff = 'destroy'
7.3 INSTALAÇÃO ASTERISK
O Asterisk lê as regras de chamadas e discagem a partir do arquivo
"extensions.conf". A linguagem dfn substituirá a configuração do "extensions.conf". Na
prática, o mecanismo do Asterisk será instruído a ler o arquivo "extensions.dfn" que
conterá toda a lógica de atendimento e regras de discagem.
As contas dos usuários continuarão a ser configuradas no arquivo sip.conf no
caso de uso do protocolo SIP. Para o IAX2, o arquivo deverá ser o iax2.conf.
47
Esse mecanismo não será alterado e não terá interação com a linguagem
propriamente dita, uma vez que esse faz parte do processo de autenticação do Asterisk,
uma camada anterior à execução do script de atendimento em dfn.
7.3.1 INTERAÇÃO ENTRE O ASTERISK E O MÓDULO DA LINGUAGEM DFN
A implementação ou interface entre a linguagem dfn e o asterisk será feita no
código pbx_dfn.c. O módulo final é o pbx_dfn.so e o mecanismo obedece o fluxo
conforme as figuras 14 e 15.
Figura 15 – Processo de inicialização
Fonte: O autor
Figura 16 – Tratamento de chamada
Fonte: O autor
48
Figura 17 – Compilação do módulo
Fonte: O autor
A figura 17 mostra a compilação do módulo do Asterisk utilizando o arquivo
pbx_dfn e a Figura 18 exibe o diretório de módulos com o arquivo pbx_dfn.so.
Figura 18 – Diretório de módulos do Asterisk
Fonte: O autor
49
O Asterisk lerá o arquivo extensions.dfn onde todas as regras de atendimento
estarão declaradas. Como as regras de atendimento do Asterisk são baseadas em
contexto, a linguagem dfn tratará essa regra como regra de entrada e executará as
funções internas do Asterisk responsáveis pelo controle de chamadas, geração de CDRs,
desligamento de chamadas, etc.
Abaixo segue o trecho do código do pbx_dfn.c das partes mais importantes
responsáveis pela integração entre o Asterisk e a linguagem dfn.
A API do Asterisk trabalha com as funções load_module, unload_module,
reload e AST_MODULE_INFO. Essas quatro funções são o coração da integração entre
qualquer modulo e o Asterisk. Quando o modulo é carregado, o asterisk lê os
parâmetros passados à macro AST_MODULE_INFO. A partir deste instante cada
função é executada conforme a ação do Asterisk. Deve-se, obrigatoriamente, declarar o
nome o arquivo padrão na variável config, o nome do módulo na variável registrar,
todas como static para ponteiro do tipo char.
static char *config = "extensions.dfn";
static char *registrar = "pbx_dfn";
A função load_module é a responsável pela carga do módulo da linguagem.
Quando o módulo é carregado, a função deverá retornar 2 possíveis valores declarados
como constantes (#define): AST_MODULE_LOAD_SUCCESS no caso de sucesso na
carga ou AST_MODULE_LOAD_DECLINE para a situação de exceção ou erro no
módulo.
static int load_module(void)
{
int res;
if ((res = load_or_reload_dfn_stuff()))
return res;
if (ast_register_switch(&dfn_switch)) {
ast_log(LOG_ERROR, "Unable to register DFN Language Extension
Modulen");
50
return AST_MODULE_LOAD_DECLINE;
}
return AST_MODULE_LOAD_SUCCESS;
}
A função unload_module tem como objetivo a remoção do módulo da memória
quando solicitado pelo usuário via console ou por situação de exceção interna do
Asterisk. Duas outras funções internas devem ser chamadas: ast_context_destroy, que
informa ao asterisk qual modulo será removido ou desregistrado e a função
ast_unregister_switch que receberá o ponteiro da função do motor da linguagem
propriamente dita.
static int unload_module(void)
{
ast_context_destroy(NULL, registrar);
ast_unregister_switch(&dfn_switch);
dfn_free_extensions();
return 0;
}
A função reload tem como objetivo chamar a função load_or_reload_dfn_stuff
que apenas remove e recarrega a linguagem dfn.
static int reload(void)
{
return load_or_reload_dfn_stuff();
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "DFN
Language Extension Module",
.load = load_module,
.unload = unload_module,
.reload = reload,
);
51
Abaixo segue exemplo do arquivo de configuração dos módulos do Asterisk
juntamente com os comentários explicativos de cada parte do arquivo e o arquivo
sip.conf:
[modules]
; autoload habilitado, instrui o Asterisk a carregar todos os arquivos *.so que encontrar
em /var/lib/asterisk/modules
autoload=yes
; Cada módulo precisa ser carregado antes do núcleo do Asterisk ser inicializado.
;
; A linha abaixo só deverá ser descomentada se o autoload for igual a "no".
;load => pbx_dfn.so
; Como o autoload está habilitado, caso não se pretenda carregar o módulo da
linguagem dfn,
; deve-se remover o comentário da linha abaixo
;noload => pbx_dfn.so
Figura 19 – Arquivo sip.conf
Fonte: O autor
7.4 DESENVOLVIMENTO DA LINGUAGEM INTERPRETADA PARA SISTEMA
MULTI-PLATAFORMA
A linguagem aqui proposta, chamada de dfn, implementa as construções
fundamentais para definição de controle de fluxo como if, elseif, else, endif, while, do,
endwhile, repeat, until, funções, e tipos definidos de dados. Trata-se ainda de uma
linguagem com tipagem dinâmica.
As próximas seções procuram tratar da estrutura da linguagem, tipos de dados,
52
sintaxes, etc.
7.4.1 VARIÁVEIS E TIPOS
As varáveis do dfn deverão conter pelo menos um caractere e deve ser iniciado
por uma letra obrigatoriamente, os caracteres seguintes poderão ser outras letras,
números e sublinha. Letras maiúsculas e minúsculas são diferentes.
Exemplo:
Nomes válidos de variáveis:
a=12
a21 = “Teste”
meuValor=51
Minha_Variavel=”Ok”
Nomes inválidos de variáveis:
_12=21
21=22
*valor=12
Esses nomes não são admitidos como válidos no contexto da linguagem dfn.
A linguagem possui os seguintes tipos de variáveis, sendo que sua conversão é
automática, o que lhe confere uma tipagem dinâmica:
Tipo null - esse tipo indica um valor indefinido. Por padrão todas as variáveis
não declaradas são do tipo null, podendo, a partir desse conceito, verificar se
uma variável foi ou não declarada no sistema.
Tipo numeric - são variáveis que contêm somente números armazenados.
Tipo string - São cadeias de caracteres contendo letras, números e caracteres
especiais como "@", "%", etc.
Tipo array - São variáveis com índice numérico onde cada índice aponta para a
posição onde o valor é armazenado.
Tipo hash - São arrays associativos, ou seja, o índice pode ser qualquer caractere
ou cadeia de caractere, numérico ou string.
Tipo function - Esse tipo de dado compreende as funções declaráveis pelo
programador na linguagem. Toda função criada pelo usuário deverá ser iniciada
53
pelo comando function, seguido do nome da função com os seus parâmetros
entre parêntesis e separado por vírgula (caso haja mais de um).
7.4.2 ATRIBUIÇÕES
Para atribuição deve-se usar o sinal de igual simples “=” entre a variável e o
valor. A simples atribuição já é suficiente para a própria declaração da variável. A
atribuição pode ser simples ou múltipla. Exemplo:
Variável = Valor
O “Valor” pode ser numérico, string, array ou qualquer outro tipo de dados
permitido pela linguagem.
Já a atribuição múltipla pode ser vista no exemplo a seguir:
var1, var2, var3 = "Universidade Anhembi Morumbi", 1231, {1,2,3,"Eu
sou um valor de um array"}
No caso acima, a variável var1 é do tipo string, a var2 do tipo numérico e a var3
é um array de 4 elementos.
A atribuição múltipla permite a troca de valores armazenados em uma única
linha. Exemplo:
var1 = "Teste1"
var2 = "Teste2"
# Resultado var1="Teste1" e var2="Teste2" – Aqui é um comentário
print( "var1=",var1, " var2=", var2 )
# Faz a troca
var1, var2 = var2, var1
# Resultado var1="Teste2" e var2="Teste1"
print( "var1=",var1, " var2=", var2 )
7.4.3 OPERADORES ARITMÉTICOS E RELACIONAIS
Os operadores aritméticos são: adição, subtração, multiplicação e divisão.
Exemplos:
a = 6/3
b = 2*10
c = 5-1
d = 20+9
Os operadores relacionais disponíveis são:
< Menor que
> Maior que
<= Menor ou igual a
>= Maior ou igual a
54
== Igual a
!= Diferente de
7.4.4 ORDEM DE PRECEDÊNCIA DOS OPERADORES
Os operadores têm a ordem de precedência usual. Essa ordem pode ser mudada
com o uso de parênteses A lista abaixo apresenta os operadores, em ordem decrescente
de precedência:
^
not -(unário)
* /
+ -
7.4.5 COMENTÁRIOS
A linguagem provê recurso de inserção de comentários. Dessa forma o código
poderá ser comentado conforme a necessidade do programador. Para isso deverá ser
usado o caractere “#”.
Exemplo:
# Isso é um comentário
Variavel=123 # Comentando o código. A partir do # a linguagem vai ignorar
o trecho até o fim de linha (n)
7.4.6 FUNÇÕES DA LINGUAGEM
Para criação da linguagem foi necessário definir e criar as funções de
manipulação de string, conversão de tipos e funções básicas.
7.4.6.1 FUNÇÕES DE MANIPULAÇÃO DE STRING
Função strlen( str )
DESCRIÇÃO
Informa o tamanho de uma string.
ARGUMENTOS
str string a ser medida
RETORNO
Retorna o número de caracteres presentes na cadeia de caracteres.
EXEMPLO
print(strlen("Universidade Anhembi Morumbi"))
# imprime o valor 28.
55
Função strlower( str )
DESCRIÇÃO
Todas as letras maiúsculas passadas na variavel str são trocadas pelas minúsculas
correspondentes.
ARGUMENTOS
str string a ser transformada
RETORNO
Retorna a string transformada.
EXEMPLO
print(strlower("Teste"))
# Imprime teste.
Função strupper( str )
DESCRIÇÃO
Todas as letras minúsculas passadas na variável str são trocadas pelas maiúsculas
correspondentes.
ARGUMENTOS
str string a ser transformada
RETORNO
Retorna a string transformada.
EXEMPLO
print(strlower("Teste"))
# Imprime TESTE.
7.4.6.2 FUNÇÕES DE CONVERSÃO DE TIPOS
Função tonumber( var )
DESCRIÇÃO
Tenta converter a variavel var em um valor numérico.
ARGUMENTOS
a expressão a ser transformada em valor numérico
RETORNO
Se for possível a conversão, retornará o valor numérico, caso contrário retornará
<null>
EXEMPLO
print(tonumber("23 "), tonumber("7.1 X"), tonumber(22))
56
# imprime os valores: 23, <null>, 22
Função tostring( var )
DESCRIÇÃO
Tenta converter a variável var em um valor string.
ARGUMENTOS
a expressão a ser transformada em valor string
RETORNO
O correspondente em string
EXEMPLO
print(tostring( 22 ))
# imprime os valores: "23"
7.4.7 CONTROLE DE FLUXO E LAÇOS ITERATIVOS
Foi necessário a criação de controles de fluxo e laços iterativos que serão
descritos a seguir.
7.4.7.1 TOMADAS DE DECISÃO COM IF
O comando para tomada de decisão da linguagem DFN é o if. Sua forma é:
if expr then
bloco
endif
ou
if expr then
bloco1...
else
bloco2...
endif
ou ainda
if expr1 then
bloco1
elseif expr2 then
bloco2
57
...
elseif expr N then
bloco N
else
bloco N+1
endif
7.4.7.2 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO INÍCIO (WHILE)
A linguagem DFN possui duas opções para construção de laços iterativos, o
comando while permite que a tomada de decisão seja no inicio antes de entrar no laço.
Sua forma geral é:
while expr do
bloco
endwhile
Isto é, enquanto a expressão expr produzir um valor diferente de null e, portanto,
verdadeiro, os comandos do bloco são executados. Considere o código abaixo que
calcula o fatorial de um número armazenado na variável n:
fat = 1
i = n
while i > 0 do
fat = fat * i
i = i – 1
endwhile
Ao final da execução do código acima, fat armazena o valor do fatorial de n e i
armazena o valor zero.
7.4.7.3 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO FIM
(REPEAT/UNTIL)
Este tipo de laço é implementado pelo comando repeat/until. A validação da
condição é feita após o bloco ser executado por, pelo menos, uma vez. Sua forma geral
é:
repeat
bloco
until expr
O mesmo exemplo do fatorial acima pode ser reescrito usando o repeat/until
conforme a seguir:
fat = 1
i = 1
58
repeat
fat = fat * i
i = i + 1
until i > n
7.4.8 ANALISADOR DE EXPRESSÃO
O analisador de expressão adotado na linguagem foi baseado nas ferramentas
bison com gerador de parser em conjunto com o gerador de analisador sintático flex a
partir da gramática previamente definida.
O código resultante foi modificado para otimização da linguagem. gerando dois
fontes: y_tab.c e lex_yy.c, a implementação das funcionalidades foram escritas nos
demais arquivos "C".
A função de entrada é a dfn_execfile, ela recebe o ponteiro para o arquivo a ser
executado e chama a função dfn_parse() que por sua vez chama o yyparse() que realiza
toda a tradução ou interpretação do código junto com a função dfn_execute().
O trecho da função yyparse() é extremamente grande, assim como a
dfn_execute(), e podem ser vistos no apendice deste documento.
Segue o trecho responsável pela execução do arquivo fonte dfn:
int dfn_execfile(char *filename) {
int x, y;
y = dfn_openfile(filename);
if (y)
return 1;
x=dfn_parse();
if( x ){
dfn_closefile();
return 1;
}
dfn_closefile();
return 0;
}
Função dfn_parse(void)
59
int dfn_parse(void)
{
Byte *initcode = maincode;
err = 0;
if (yyparse() || (err == 1))
return 1;
*maincode++ = HALT;
if (dfn_execute(initcode))
return 1;
maincode = initcode;
return 0;
}
7.5 IMPLEMENTAÇÃO DA LINGUAGEM INTERPRETADA NO SISTEMA
PARAVIRTUALIZADO
O ambiente final criado para implementação e utilização da linguagem
desenvolvida nos capítulos anteriores é exemplificado através da figura 20 com uma
máquina host que porta a VM com o Asterisk instalado e configurado para utilizar a
linguagem proposta interligada a telefones através de um switch e um aparelho ATA.
Figura 20 – Topologia final
Fonte: O autor
60
Figura 21 – Módulo carregado com sucesso
Fonte: O autor
Figura 22 – Módulo não carrega sem extensions.dfn
Fonte: O autor
61
A figura 21 mostra que os módulos do Asterisk foram carregados com sucesso
utilizando a linguagem DFN.
A figura 19 mostra que o módulo foi carregado com sucesso e que o Asterisk
está pronto para fazer e receber ligações.
A figura 20 mostra que não é possível carregar os módulos do Asterisk sem
utilizar o arquivo extensions.dfn.
Figura 23 – CDR
Fonte: O autor
A figura 23 mostra o registro da chamada, também conhecido como CDR da
ligação de teste realizada.
Foram realizados testes simples de chamada entre dois ramais 4001 e 4002 onde
o asterisk executou o código abaixo:
arquivo: extensions.dfn
Código:
contexto = getcontext() # Obtém o contexto da ligação que está entrando
exten = getexten()
if contexto == "from-internal" then
Dial(SIP/exten,50,RTt) # Encaminha a chamada para o Ramal obtido da variável
extena
endif
62
Figura 24 – Ligação realizada
Fonte: O autor
A figura 23 mostra que o teste com o arquivo .dfn foi realizado com sucesso.
63
8 CONCLUSÃO
Levando-se em conta o que foi observado, pode-se concluir que uma linguagem
de programação interpretada (extensível) facilita a parametrização de aplicativos que
necessitam do uso de configuração para seu funcionamento, assim como é capaz de
permitir a inclusão de novas funcionalidades ao aplicativo. A linguagem desenvolvida
neste trabalho demonstrou que, apesar da dificuldade, em função de sua complexidade,
para criar e integrá-la a um aplicativo hospedeiro, é possível e recomendável o seu uso,
pois uma vez agregada esta funcionalidade ao hospedeiro, a linguagem embarcada
expande a capacidade de funcionamento do aplicativo em si. O ambiente criado
utilizando a paravirtualização demonstrou que é possível garantir um SLA elevado, uma
vez que na indisponibilidade de um hardware, outro poderá assumir como hospedeiro de
uma cópia da máquina paravirtualizada.
Como trabalhos futuros pode-se apontar o estudo e criação de um ambiente
altamente disponível (cluster) utilizando a paravirtualização como plataforma e o
Asterisk como software hospedeiro. Além disso, pode-se realizar trabalhos relacionados
a testes de desempenho utilizando paravirtualização e virtualização completa com
hardwares que utilizam tecnologias Intel-VT ou AMD-V.
A linguagem aqui proposta, possui potencial para a sua ampliação em trabalhos
futuros como a implementação da geração dos CDRs para ambiente de telefonia VoIP.
Trata-se de um recurso importante, pois os CDRs são os registros das chamadas
realizadas em um ambiente de telefonia.
64
REFERÊNCIAS BIBLIOGRÁFICAS
AMD. Mais eficiência na plataforma de virtualização. Disponível em:
<http://www.amd.com/br-
pt/Processors/ProductInformation/0,,30_118_8796_14287,00.html>.Acesso em: 25
maio 2010.
ARANGO, M. Media Gateway Control Protocol (MGCP). Disponível em inglês:
<http://tools.ietf.org/html/rfc2705>. Acesso em 2 jul. 2010.
ASTERISK, BRASIL. O que é o Asterisk? Disponível em:
<http://www.asteriskbrasil.org/>. Acesso em: 20 set. 2010.
ASTERISK. Asterisk Coding Guideline. Disponível em inglês:
<http://www.asterisk.org/developers/coding-guidelines>. Acesso em 10 out 2010.
BELLARD, Fabrice. QEMU, a Fast and Portable Dynamic Translator. Disponível
em inglês:
<http://www.usenix.org/publications/library/proceedings/usenix05/tech/freenix/full_pap
ers/bellard/bellard.pdf>. Acesso em: 29 maio 2010.
BOCHS. Welcome to the Bochs IA-32 Emulator Project. Disponível em inglês:
<http://bochs.sourceforge.net/>. Acesso em: 25 maio 2010.
CASSIMIRI, Alexandre. Virtualização: da teoria a soluções. Porto Alegre: Ufrgs,
2008. 207 p. Disponível em:
<http://www.gta.ufrj.br/ensino/CPE758/artigos-basicos/cap4-v2.pdf>. Acesso em: 20
maio 2010.
CALDAS, Anderson. Introdução a Linguagens de Programação. Alagoas:
Universidade Federal de Alagoas, 2010. 18 slides. Disponível em:
<http://www.lccv.ufal.br/downloads/cursos/curso-basico-de-c-
2010/arquivos/apresentacoes/Aula%2001.1%20-
%20Introducao%20a%20Linguagem%20de%20Programacao%20C.pptx/>. Acesso em:
10 de jul. 2010.
CARTER, Nicholas. Arquitetura de Computadores. Illinois, 2002. 236 p.
CHANTRY, Darryl. Mapping applications to the cloud. Disponível em inglês:
<http://msdn.microsoft.com/en-us/library/dd430340.aspx>. Acesso em: 28 abr. 2010.
CREASY, R. J.. IBM Journal of Research and Development: The origin of the
VM/370 time-sharing system. v. 25, n. 5, p. 483–490 Palo Alto, Ca, Usa: Ibm, 1981.
Disponível em inglês:
<http://pages.cs.wisc.edu/~stjones/proj/vm_reading/ibmrd2505M.pdf>. Acesso em: 25
abr. 2010.
DAVENPORT, Malcolm. Asterisk as a Swiss Army Knife of Telephony. Disponível
em inglês:
65
<https://wiki.asterisk.org/wiki/display/AST/Asterisk+as+a+Swiss+Army+Knife+of+Tel
ephony>Acesso em: 20 set. 2010.
DIKE, Jeff. The User-mode Linux Kernel Home Page. Disponível em inglês: <
http://user-mode-linux.sourceforge.net/>. Acesso em: 25 abr. 2010.
FIGUEIREDO, Luiz Henrique de; IERUSALIMSCHY, Roberto; CELES, Waldemar. A
Linguagem Lua e suas aplicações em jogos. Disponível em:
<http://www.lua.org/doc/wjogos04.pdf>. Acesso em: 09 abr. 2010.
GARTNER. Special Report Virtualization. Disponível em inglês:
<http://www.gartner.com/it/products/research/virtualization/virtualization.jsp?ref=3_28
_08LR>. Acesso em: 25 abr. 2010.
GOLDEN, Bernard; SHEFFY, Clark. Virtualization for Dummies. Indianapolis:
Wiley, 2008. 50 p. Disponível em inglês:
<http://www.pcworld.com.vn/Handler/FileDowload.ashx?fileId=5150>. Acesso em: 02
maio 2010.
GUY, Ed. IANA Registration for IAX. Disponível em inglês:
<http://tools.ietf.org/html/draft-ietf-enum-iax-05>. Acesso em: 02 jul. 2010.
IBM. Compiled versus Interpreted languages. Disponível em inglês:
<http://publib.boulder.ibm.com/infocenter/zos/basics/topic/com.ibm.zos.zappldev/zappl
dev_85.htm>. Acesso em 21 set. 2010.
IBM. IBM Systems Virtualization. Version 2 Release 1. Disponível em inglês:
<http://publib.boulder.ibm.com/infocenter/eserver/v1r2/topic/eicay/eicay.pdf>. Acesso
em 20 mai. 2010.
IBM; JONES, M. Tim. Virtual Linux. Disponível em inglês:
<http://www.ibm.com/developerworks/library/l-linuxvirt/>. Acesso em: 02 jun. 2010.
IETF. Session Initiation Protocol (sip). Disponível em inglês:
<http://datatracker.ietf.org/wg/sip/charter/>. Acesso em 05 jul. 2010.
INTEL. Virtualization. Disponível em inglês:
<http://www.intel.com/technology/virtualization/>. Acesso em: 25 maio 2010.
JONES, M. Tim. Virtual Linux. An overview of virtualization methods,
architetures and implementations. Disponível em inglês:
<http://www.ibm.com/developerworks/linux/library/l-linuxvirt/>. Acesso em: 29 abr.
2010.
KVM. Kernel Based Virtual Machine. Disponível em inglês:
<http://www.linux-kvm.org>. Acesso em: 31 maio 2010.
66
LOUDEN, C. Kenneth. Compiladores. Princípios e práticas. San Jose State
University, 2004, 569 p.
MANFRIN, Alexander. História: Conhecendo a origem da virtualização. Disponível
em:
<http://www.vmworld.com.br/br/index.php?option=com_content&view=article&id=80:
historia-conhecendo-a-origem-da-virtualizacao&catid=50:virtualizacao>. Acesso em 20
maio 2010.
MENASCÉ, Daniel A. Virtualization: Concepts, Applications, and performance
modelling. Disponível em inglês:
<http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.61.6680&rep=rep1&type=p
df>. Acesso em: 20 maio 2010.
MICROSOFT. Hyper-V Server 2008 R2. Disponível em:
<http://www.microsoft.com/brasil/servidores/hyper-v-server/default.mspx>. Acesso em:
31 maio 2010.
ORIGUELA, Marcos. Paravirtualização com o Xen. Disponível em:
<http://www.vivaolinux.com.br/artigo/Paravirtualizacao-com-o-Xen/>. Acesso em 29
maio 2010.
PETTEY, Christy. Gartner Says Virtualization Will Be the Highest-Impact Trend
in Infrastructure and Operations Market Through 2012. Disponível em inglês:
<http://www.gartner.com/it/page.jsp?id=638207>. Acesso em: 25 abr. 2010.
PROEBSTING, Todd A. Disruptive Programming Language Technologies:
Microsoft Research. Disponível em inglês:
<http://research.microsoft.com/en-us/um/people/toddpro/papers/disruptive.ppt>. Acesso
em: 09 abr. 2010.
QEMU. About. Disponível em inglês: <www.qemu.org>. Acesso em: 29 maio 2010.
SEBESTA, Robert W. Conceitos de linguagem de programação. 5º Edição, 2002.
634 p.
SHIELDS, Greg. The Shortcut Guide to Selecting the Right Virtualization
Solution. San Francisco: Realtime Publishers, 2008. 72 p. Disponível em inglês:
<http://nexus.realtimepublishers.com/sgsrvs.php>. Acesso em: 01 maio 2010.
Stanford University. Interpreted Languages. Disponível em inglês:
<http://pangea.stanford.edu/computerinfo/unix/programming/interpreted/>. Acesso em
10 ago. 2010.
UBERHIP. Paravirtualization. Disponível em:
<http://uberhip.com/godber/plug/Xen_Primer/assets/paravirtualization.png>. Acesso
em: 02 maio 2010.
VMWARE. Deploy the Most Advanced and Production-Proven
Hypervisors. Disponível em inglês:
67
<http://www.vmware.com/products/esx/index.html>. Acesso em: 30 maio 2010.
VMWARE. History of Virtualization. Disponível em inglês:
<http://www.vmware.com/virtualization/history.html>. Acesso em: 02 abr. 2010.
VMWARE, Understanding Full Virtualization, Paravirtualization, and Hardware
Assist. Disponível em inglês:
<http://www.vmware.com/files/pdf/VMware_paravirtualization.pdf>.Acesso em 03
abr. 2010.
XEN. What is in Xen. Disponível em inglês: <http://www.xen.org/>. Acesso em: 01
jun. 2010.
XEN. Xen Architecture Overview. Disponível em inglês:
<http://wiki.xen.org/xenwiki/XenArchitecture?action=AttachFile&do=get&target=Xen
+Architecture_Q1+2008.pdf>. Acesso em: 2 jun. 2010.
68
APÊNDICE A – CÓDIGO FONTE DA LINGUAGEM
/*
* dfn.c
*
* Programa criado para demonstracao de uso standalone da linguagem
dfn
*/
#include <stdio.h>
#include "dfn.h"
#include "dfnlib.h"
int main(int argc, char *argv[]) {
if (argc < 2) {
puts("Usage: dfn <filename.dfn>");
return 0;
}
dfn_execfile(argv[1]);
return 0;
}
/*
**DFN.h
*/
#ifndef dfn_h
#define dfn_h
typedef void (*dfn_CFunction) (void);
typedef struct Object *dfn_Object;
#define dfn_register(ref,func) (dfn_globalref(ref),
dfn_pushcfunction(func))
void dfn_errorfunction(void (*fn) (char *s));
void dfn_error(char *s);
int dfn_execfile(char *filename);
int dfn_dostring(char *string);
int dfn_call(char *functionname, int nparam);
dfn_Object dfn_getparam(int number);
float dfn_getnumber(dfn_Object object);
char *dfn_getstring(dfn_Object object);
char *dfn_copystring(dfn_Object object);
dfn_CFunction dfn_getcfunction(dfn_Object object);
void *dfn_getuserdata(dfn_Object object);
dfn_Object dfn_getfield(dfn_Object object, char *field);
dfn_Object dfn_getindexed(dfn_Object object, float index);
dfn_Object dfn_getglobal(char *name);
dfn_Object dfn_pop(void);
int dfn_pushnil(void);
int dfn_pushnumber(float n);
69
int dfn_pushstring(char *s);
int dfn_pushcfunction(dfn_CFunction fn);
int dfn_pushuserdata(void *u);
int dfn_pushobject(dfn_Object object);
int dfn_globalref(char *name);
int dfn_storefield(dfn_Object object, char *field);
int dfn_storeindexed(dfn_Object object, float index);
int dfn_isnil(dfn_Object object);
int dfn_isnumber(dfn_Object object);
int dfn_isstring(dfn_Object object);
int dfn_istable(dfn_Object object);
int dfn_iscfunction(dfn_Object object);
int dfn_isuserdata(dfn_Object object);
#endif
/*
** hash.c
*/
#include <string.h>
#include <stdlib.h>
#include "objects.h"
#include "hash.h"
#include "inout.h"
#include "table.h"
#include "dfn.h"
// Pseudofuncs
#define streq(s1,s2) (strcmp(s1,s2)==0)
#define strneq(s1,s2) (strcmp(s1,s2)!=0)
// Encapsulando as funcoes de alocacao de memoria do C
#define new(s) ((s *)malloc(sizeof(s)))
#define newvector(n,s) ((s *)calloc(n,sizeof(s)))
#define nhash(t) ((t)->nhash)
#define nodelist(t) ((t)->list)
#define list(t,i) ((t)->list[i])
#define ref_tag(n) (tag(&(n)->ref))
#define ref_nvalue(n) (nvalue(&(n)->ref))
#define ref_svalue(n) (svalue(&(n)->ref))
static int head(Hash * t, Object * ref)
{
if (tag(ref) == T_NUMBER)
return (((int) nvalue(ref)) % nhash(t));
else if (tag(ref) == T_STRING) {
int h;
char *name = svalue(ref);
for (h = 0; *name != 0; name++) { /* name as bin */
h <<= 8;
h += (unsigned char) *name;
h %= nhash(t);
}
return h;
} else {
70
dfn_reportbug("unexpected type to index table");
return -1;
}
}
static Node *present(Hash * t, Object * ref, int h)
{
Node *n = NULL, *p;
if (tag(ref) == T_NUMBER) {
for (p = NULL, n = list(t, h); n != NULL; p = n, n = n-
>next)
if (ref_tag(n) == T_NUMBER && nvalue(ref) ==
ref_nvalue(n))
break;
} else if (tag(ref) == T_STRING) {
for (p = NULL, n = list(t, h); n != NULL; p = n, n = n-
>next)
if (ref_tag(n) == T_STRING &&
streq(svalue(ref), ref_svalue(n)))
break;
}
if (n == NULL)
return NULL;
return n;
}
static void freelist(Node * n)
{
while (n) {
Node *next = n->next;
free(n);
n = next;
}
}
/*
*/
Hash *dfn_hashcreate(unsigned int nhash)
{
Hash *t = new(Hash);
if (t == NULL) {
dfn_error("not enough memory");
return NULL;
}
nhash(t) = nhash;
markarray(t) = 0;
nodelist(t) = newvector(nhash, Node *);
if (nodelist(t) == NULL) {
dfn_error("not enough memory");
return NULL;
}
return t;
}
/*
*/
void dfn_hashdelete(Hash * h)
{
int i;
for (i = 0; i < nhash(h); i++)
71
freelist(list(h, i));
free(nodelist(h));
free(h);
}
/*
*/
Object *dfn_hashdefine(Hash * t, Object * ref)
{
int h;
Node *n;
h = head(t, ref);
if (h < 0)
return NULL;
n = present(t, ref, h);
if (n == NULL) {
n = new(Node);
if (n == NULL) {
dfn_error("not enough memory");
return NULL;
}
n->ref = *ref;
tag(&n->val) = T_NIL;
n->next = list(t, h);
list(t, h) = n;
}
return (&n->val);
}
/*
*/
void dfn_hashmark(Hash * h)
{
int i;
markarray(h) = 1;
for (i = 0; i < nhash(h); i++) {
Node *n;
for (n = list(h, i); n != NULL; n = n->next) {
dfn_markobject(&n->ref);
dfn_markobject(&n->val);
}
}
}
/*
*/
#include "dfn.h"
static void firstnode(Hash * a, int h)
{
if (h < nhash(a)) {
int i;
for (i = h; i < nhash(a); i++) {
if (list(a, i) != NULL && tag(&list(a, i)->val)
!= T_NIL) {
dfn_pushobject(&list(a, i)->ref);
dfn_pushobject(&list(a, i)->val);
return;
72
}
}
}
dfn_pushnil();
dfn_pushnil();
}
void dfn_next(void)
{
Hash *a;
Object *o = dfn_getparam(1);
Object *r = dfn_getparam(2);
if (o == NULL || r == NULL) {
dfn_error("too few arguments to function `next'");
return;
}
if (dfn_getparam(3) != NULL) {
dfn_error("too many arguments to function `next'");
return;
}
if (tag(o) != T_ARRAY) {
dfn_error("first argument of function `next' is not a
table");
return;
}
a = avalue(o);
if (tag(r) == T_NIL) {
firstnode(a, 0);
return;
} else {
int h = head(a, r);
if (h >= 0) {
Node *n = list(a, h);
while (n) {
if (memcmp(&n->ref, r, sizeof(Object))
== 0) {
if (n->next == NULL) {
firstnode(a, h + 1);
return;
} else if (tag(&n->next->val) !=
T_NIL) {
dfn_pushobject(&n->next-
>ref);
dfn_pushobject(&n->next-
>val);
return;
} else {
Node *next = n->next-
>next;
while (next != NULL &&
tag(&next->val) == T_NIL)
next = next-
>next;
if (next == NULL) {
firstnode(a, h +
1);
return;
} else {
dfn_pushobject(&next->ref);
73
dfn_pushobject(&next->val);
}
return;
}
}
n = n->next;
}
if (n == NULL)
dfn_error("error in function 'next':
reference not found");
}
}
}
/*
** hash.h
*/
#ifndef hash_h
#define hash_h
typedef struct node {
Object ref;
Object val;
struct node *next;
} Node;
typedef struct Hash {
char mark;
unsigned int nhash;
Node **list;
} Hash;
#define markarray(t) ((t)->mark)
Hash *dfn_hashcreate(unsigned int nhash);
void dfn_hashdelete(Hash * h);
Object *dfn_hashdefine(Hash * t, Object * ref);
void dfn_hashmark(Hash * h);
void dfn_next(void);
#endif
/*
** inout.c
*/
#include <stdio.h>
#include <string.h>
#include "objects.h"
#include "hash.h"
#include "inout.h"
#include "table.h"
/* Exported variables */
74
int dfn_linenumber;
int dfn_debug;
int dfn_debugline;
/* Internal variables */
#ifndef MAXFUNCSTACK
#define MAXFUNCSTACK 32
#endif
static struct {
int file;
int function;
} funcstack[MAXFUNCSTACK];
static int nfuncstack = 0;
static FILE *fp;
static char *st;
static void (*usererror) (char *s);
/*
*/
void dfn_errorfunction(void (*fn) (char *s))
{
usererror = fn;
}
/*
*/
static int fileinput(void)
{
int c = fgetc(fp);
int ntemp=c;
return (c == EOF ? 0 : c);
}
/*
*/
static void fileunput(int c)
{
ungetc(c, fp);
}
/*
*/
static int stringinput(void)
{
st++;
return (*(st - 1));
}
/*
*/
static void stringunput(int c)
{
st--;
}
/*
*/
int dfn_openfile(char *fn)
{
dfn_linenumber = 1;
75
dfn_setinput(fileinput);
dfn_setunput(fileunput);
fp = fopen(fn, "r");
if (fp == NULL)
return 1;
if (dfn_addfile(fn))
return 1;
return 0;
}
/*
*/
void dfn_closefile(void)
{
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
}
/*
*/
int dfn_openstring(char *s)
{
dfn_linenumber = 1;
dfn_setinput(stringinput);
dfn_setunput(stringunput);
st = s;
{
char sn[64];
sprintf(sn, "String: %10.10s...", s);
if (dfn_addfile(sn))
return 1;
}
return 0;
}
/*
*/
void dfn_error(char *s)
{
if (usererror != NULL)
usererror(s);
else
fprintf(stderr, "dfn: %sn", s);
}
/*
*/
int dfn_pushfunction(int file, int function)
{
if (nfuncstack >= MAXFUNCSTACK - 1) {
dfn_error("function stack overflow");
return 1;
}
funcstack[nfuncstack].file = file;
funcstack[nfuncstack].function = function;
nfuncstack++;
return 0;
}
76
/*
*/
void dfn_popfunction(void)
{
nfuncstack--;
}
/*
*/
void dfn_reportbug(char *s)
{
char msg[1024];
strcpy(msg, s);
if (dfn_debugline != 0) {
int i;
if (nfuncstack > 0) {
sprintf(strchr(msg, 0),
"ntin statement begining at
line %d in function "%s" of file "%s"",
dfn_debugline,
s_name(funcstack[nfuncstack -
1].function),
dfn_file[funcstack[nfuncstack -
1].file]);
sprintf(strchr(msg, 0), "ntactive stackn");
for (i = nfuncstack - 1; i >= 0; i--)
sprintf(strchr(msg, 0),
"t-> function "%s" of
file "%s"n",
s_name(funcstack[i].function), dfn_file[funcstack[i].file]);
} else {
sprintf(strchr(msg, 0),
"ntin statement begining at
line %d of file "%s"",
dfn_debugline, dfn_filename());
}
}
dfn_error(msg);
}
/*
** inout.h
*/
#ifndef inout_h
#define inout_h
extern int dfn_linenumber;
extern int dfn_debug;
extern int dfn_debugline;
int dfn_openfile(char *fn);
void dfn_closefile(void);
int dfn_openstring(char *s);
int dfn_pushfunction(int file, int function);
void dfn_popfunction(void);
void dfn_reportbug(char *s);
#endif
77
/*
** lex_yy.c
*/
# include "stdio.h"
#define LEXDEBUG 1
# define U(x) x
# define NLSTATE yyprevious=YYNEWLINE
# define BEGIN yybgin = yysvec + 1 +
# define INITIAL 0
# define YYLERR yysvec
# define YYSTATE (yyestate-yysvec-1)
# define YYOPTIM 1
# define YYLMAX BUFSIZ
# define output(c) putc(c,yyout)
# define input() (((yytchar=yysptr>yysbuf?U(*--
yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
# define unput(c) {yytchar= (c);if(yytchar=='n')yylineno--
;*yysptr++=yytchar;}
# define yymore() (yymorfg=1)
# define ECHO fprintf(yyout, "%s",yytext)
# define REJECT { nstr = yyreject(); goto yyfussy;}
int yyleng;
extern char yytext[];
int yymorfg;
extern char *yysptr, yysbuf[];
int yytchar;
FILE *yyin = { NULL }, *yyout = {
NULL};
extern int yylineno;
struct yysvf {
struct yywork *yystoff;
struct yysvf *yyother;
int *yystops;
};
struct yysvf *yyestate;
extern struct yysvf yysvec[], *yybgin;
#include <stdlib.h>
#include <string.h>
#include "objects.h"
#include "hash.h"
#include "inout.h"
#include "table.h"
#include "y_tab.h"
#undef input
#undef unput
static Input input;
static Unput unput;
void dfn_setinput(Input fn)
{
input = fn;
}
void dfn_setunput(Unput fn)
78
{
unput = fn;
}
char *dfn_lasttext(void)
{
return yytext;
}
# define YYNEWLINE 10
yylex()
{
int nstr;
extern int yyprevious;
while ((nstr = yylook()) >= 0)
yyfussy:switch (nstr) {
case 0:
if (yywrap())
return (0);
break;
case 1:
;
break;
case 2:
{
yylval.vInt = 1;
return DEBUG;
}
break;
case 3:
{
yylval.vInt = 0;
return DEBUG;
}
break;
case 4:
dfn_linenumber++;
break;
case 5:
;
break;
case 6:
return LOCAL;
break;
case 7:
return IF;
break;
case 8:
return THEN;
break;
case 9:
return ELSE;
break;
case 10:
return ELSEIF;
break;
case 11:
return WHILE;
79
break;
case 12:
return DO;
break;
case 13:
return REPEAT;
break;
case 14:
return UNTIL;
break;
case 15:
{
yylval.vWord = dfn_nfile - 1;
return FUNCTION;
}
break;
case 16:
return END;
break;
case 17:
return RETURN;
break;
case 18:
return LOCAL;
break;
case 19:
return NIL;
break;
case 20:
return AND;
break;
case 21:
return OR;
break;
case 22:
return NOT;
break;
case 23:
return NE;
break;
case 24:
return LE;
break;
case 25:
return GE;
break;
case 26:
return CONC;
break;
case 27:
case 28:
{
yylval.vWord =
dfn_findenclosedconstant(yytext);
return STRING;
}
break;
case 29:
case 30:
case 31:
case 32:
80
{
yylval.vFloat = atof(yytext);
return NUMBER;
}
break;
case 33:
{
yylval.vWord = dfn_findsymbol(yytext);
return NAME;
}
break;
case 34:
return *yytext;
break;
case -1:
break;
default:
fprintf(yyout, "bad switch yylook %d", nstr);
}
return (0);
}
/* end of yylex */
int yyvstop[] = {
0,
1,
0,
1,
0,
34,
0,
1,
34,
0,
4,
0,
34,
0,
34,
0,
34,
0,
34,
0,
29,
34,
0,
34,
0,
81
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
33,
34,
0,
34,
0,
34,
0,
82
1,
0,
27,
0,
28,
0,
5,
0,
26,
0,
30,
0,
29,
0,
29,
0,
24,
0,
25,
0,
33,
0,
33,
0,
12,
33,
0,
33,
0,
33,
0,
33,
0,
7,
33,
0,
33,
0,
33,
0,
33,
0,
83
21,
33,
0,
33,
0,
33,
0,
33,
0,
33,
0,
23,
0,
29,
30,
0,
31,
0,
20,
33,
0,
33,
0,
16,
33,
0,
33,
0,
33,
0,
19,
33,
0,
22,
33,
0,
33,
0,
33,
0,
33,
0,
84
33,
0,
33,
0,
32,
0,
9,
33,
0,
33,
0,
33,
0,
33,
0,
33,
0,
8,
33,
0,
33,
0,
33,
0,
31,
32,
0,
33,
0,
33,
0,
6,
18,
33,
0,
33,
0,
33,
0,
14,
33,
0,
11,
85
33,
0,
10,
33,
0,
33,
0,
13,
33,
0,
17,
33,
0,
2,
0,
33,
0,
15,
33,
0,
3,
0,
0
};
# define YYTYPE char
struct yywork {
YYTYPE verify, advance;
} yycrank[] = {
0, 0, 0, 0, 1, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 4, 1, 5,
6, 29, 4, 28, 0, 0, 0, 0,
0, 0, 0, 0, 7, 31, 0, 0,
6, 29, 6, 29, 0, 0, 0, 0,
0, 0, 0, 0, 7, 31, 7, 31,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 6,
4, 28, 0, 0, 0, 0, 0, 0,
1, 7, 0, 0, 0, 0, 0, 0,
1, 3, 6, 30, 1, 8, 1, 9,
0, 0, 1, 10, 6, 29, 7, 31,
8, 33, 0, 0, 6, 29, 0, 0,
7, 32, 0, 0, 0, 0, 6, 29,
7, 31, 1, 11, 0, 0, 1, 12,
2, 27, 7, 31, 1, 13, 11, 39,
12, 40, 1, 13, 26, 56, 0, 0,
0, 0, 2, 8, 2, 9, 0, 0,
6, 29, 0, 0, 0, 0, 6, 29,
0, 0, 0, 0, 7, 31, 0, 0,
0, 0, 7, 31, 0, 0, 0, 0,
2, 11, 0, 0, 2, 12, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
86
0, 0, 0, 0, 1, 14, 0, 0,
0, 0, 1, 15, 1, 16, 1, 17,
0, 0, 22, 52, 1, 18, 18, 47,
23, 53, 1, 19, 42, 63, 1, 20,
1, 21, 25, 55, 14, 42, 1, 22,
15, 43, 1, 23, 1, 24, 16, 44,
1, 25, 16, 45, 17, 46, 19, 48,
21, 51, 2, 14, 20, 49, 1, 26,
2, 15, 2, 16, 2, 17, 24, 54,
20, 50, 2, 18, 44, 64, 45, 65,
2, 19, 46, 66, 2, 20, 2, 21,
27, 57, 48, 67, 2, 22, 49, 68,
2, 23, 2, 24, 50, 69, 2, 25,
52, 70, 53, 72, 27, 58, 54, 73,
52, 71, 9, 34, 2, 26, 9, 35,
9, 35, 9, 35, 9, 35, 9, 35,
9, 35, 9, 35, 9, 35, 9, 35,
9, 35, 10, 36, 55, 74, 10, 37,
10, 37, 10, 37, 10, 37, 10, 37,
10, 37, 10, 37, 10, 37, 10, 37,
10, 37, 57, 75, 58, 76, 64, 80,
66, 81, 67, 82, 70, 83, 71, 84,
72, 85, 73, 86, 74, 87, 10, 38,
10, 38, 38, 61, 10, 38, 38, 61,
75, 88, 76, 89, 38, 62, 38, 62,
38, 62, 38, 62, 38, 62, 38, 62,
38, 62, 38, 62, 38, 62, 38, 62,
80, 92, 81, 93, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
82, 94, 83, 95, 84, 96, 10, 38,
10, 38, 86, 97, 10, 38, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 87, 98, 88, 99, 60, 79,
60, 79, 13, 41, 60, 79, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 13, 41, 13, 41, 13, 41,
13, 41, 33, 33, 89, 100, 60, 79,
60, 79, 92, 101, 60, 79, 93, 102,
95, 103, 33, 33, 33, 0, 96, 104,
99, 105, 100, 106, 102, 107, 106, 108,
107, 109, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 108, 110,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 33, 33, 0, 0,
0, 0, 35, 59, 35, 59, 33, 33,
35, 59, 0, 0, 0, 0, 33, 33,
0, 0, 0, 0, 0, 0, 0, 0,
33, 33, 0, 0, 0, 0, 0, 0,
0, 0, 36, 60, 36, 60, 36, 60,
36, 60, 36, 60, 36, 60, 36, 60,
87
36, 60, 36, 60, 36, 60, 0, 0,
0, 0, 33, 33, 0, 0, 0, 0,
33, 33, 35, 59, 35, 59, 0, 0,
35, 59, 36, 38, 36, 38, 59, 77,
36, 38, 59, 77, 0, 0, 0, 0,
59, 78, 59, 78, 59, 78, 59, 78,
59, 78, 59, 78, 59, 78, 59, 78,
59, 78, 59, 78, 61, 62, 61, 62,
61, 62, 61, 62, 61, 62, 61, 62,
61, 62, 61, 62, 61, 62, 61, 62,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 36, 38, 36, 38, 0, 0,
36, 38, 77, 78, 77, 78, 77, 78,
77, 78, 77, 78, 77, 78, 77, 78,
77, 78, 77, 78, 77, 78, 79, 90,
0, 0, 79, 90, 0, 0, 0, 0,
79, 91, 79, 91, 79, 91, 79, 91,
79, 91, 79, 91, 79, 91, 79, 91,
79, 91, 79, 91, 90, 91, 90, 91,
90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91,
90, 91, 0, 0};
struct yysvf yysvec[] = {
0, 0, 0,
yycrank + -1, 0, yyvstop + 1,
yycrank + -28, yysvec + 1, yyvstop + 3,
yycrank + 0, 0, yyvstop + 5,
yycrank + 4, 0, yyvstop + 7,
yycrank + 0, 0, yyvstop + 10,
yycrank + -11, 0, yyvstop + 12,
yycrank + -17, 0, yyvstop + 14,
yycrank + 7, 0, yyvstop + 16,
yycrank + 107, 0, yyvstop + 18,
yycrank + 119, 0, yyvstop + 20,
yycrank + 6, 0, yyvstop + 23,
yycrank + 7, 0, yyvstop + 25,
yycrank + 158, 0, yyvstop + 27,
yycrank + 4, yysvec + 13, yyvstop + 30,
yycrank + 5, yysvec + 13, yyvstop + 33,
yycrank + 11, yysvec + 13, yyvstop + 36,
yycrank + 5, yysvec + 13, yyvstop + 39,
yycrank + 5, yysvec + 13, yyvstop + 42,
yycrank + 12, yysvec + 13, yyvstop + 45,
yycrank + 21, yysvec + 13, yyvstop + 48,
yycrank + 10, yysvec + 13, yyvstop + 51,
yycrank + 4, yysvec + 13, yyvstop + 54,
yycrank + 4, yysvec + 13, yyvstop + 57,
yycrank + 21, yysvec + 13, yyvstop + 60,
yycrank + 9, yysvec + 13, yyvstop + 63,
yycrank + 9, 0, yyvstop + 66,
yycrank + 40, 0, yyvstop + 68,
yycrank + 0, yysvec + 4, yyvstop + 70,
yycrank + 0, yysvec + 6, 0,
yycrank + 0, 0, yyvstop + 72,
yycrank + 0, yysvec + 7, 0,
yycrank + 0, 0, yyvstop + 74,
yycrank + -280, 0, yyvstop + 76,
yycrank + 0, 0, yyvstop + 78,
yycrank + 249, 0, yyvstop + 80,
yycrank + 285, 0, yyvstop + 82,
yycrank + 0, yysvec + 10, yyvstop + 84,
yycrank + 146, 0, 0,
88
yycrank + 0, 0, yyvstop + 86,
yycrank + 0, 0, yyvstop + 88,
yycrank + 0, yysvec + 13, yyvstop + 90,
yycrank + 10, yysvec + 13, yyvstop + 92,
yycrank + 0, yysvec + 13, yyvstop + 94,
yycrank + 19, yysvec + 13, yyvstop + 97,
yycrank + 35, yysvec + 13, yyvstop + 99,
yycrank + 27, yysvec + 13, yyvstop + 101,
yycrank + 0, yysvec + 13, yyvstop + 103,
yycrank + 42, yysvec + 13, yyvstop + 106,
yycrank + 35, yysvec + 13, yyvstop + 108,
yycrank + 30, yysvec + 13, yyvstop + 110,
yycrank + 0, yysvec + 13, yyvstop + 112,
yycrank + 36, yysvec + 13, yyvstop + 115,
yycrank + 48, yysvec + 13, yyvstop + 117,
yycrank + 35, yysvec + 13, yyvstop + 119,
yycrank + 61, yysvec + 13, yyvstop + 121,
yycrank + 0, 0, yyvstop + 123,
yycrank + 76, 0, 0,
yycrank + 67, 0, 0,
yycrank + 312, 0, 0,
yycrank + 183, yysvec + 36, yyvstop + 125,
yycrank + 322, 0, 0,
yycrank + 0, yysvec + 61, yyvstop + 128,
yycrank + 0, yysvec + 13, yyvstop + 130,
yycrank + 78, yysvec + 13, yyvstop + 133,
yycrank + 0, yysvec + 13, yyvstop + 135,
yycrank + 81, yysvec + 13, yyvstop + 138,
yycrank + 84, yysvec + 13, yyvstop + 140,
yycrank + 0, yysvec + 13, yyvstop + 142,
yycrank + 0, yysvec + 13, yyvstop + 145,
yycrank + 81, yysvec + 13, yyvstop + 148,
yycrank + 66, yysvec + 13, yyvstop + 150,
yycrank + 74, yysvec + 13, yyvstop + 152,
yycrank + 80, yysvec + 13, yyvstop + 154,
yycrank + 78, yysvec + 13, yyvstop + 156,
yycrank + 94, 0, 0,
yycrank + 93, 0, 0,
yycrank + 341, 0, 0,
yycrank + 0, yysvec + 77, yyvstop + 158,
yycrank + 356, 0, 0,
yycrank + 99, yysvec + 13, yyvstop + 160,
yycrank + 89, yysvec + 13, yyvstop + 163,
yycrank + 108, yysvec + 13, yyvstop + 165,
yycrank + 120, yysvec + 13, yyvstop + 167,
yycrank + 104, yysvec + 13, yyvstop + 169,
yycrank + 0, yysvec + 13, yyvstop + 171,
yycrank + 113, yysvec + 13, yyvstop + 174,
yycrank + 148, yysvec + 13, yyvstop + 176,
yycrank + 133, 0, 0,
yycrank + 181, 0, 0,
yycrank + 366, 0, 0,
yycrank + 0, yysvec + 90, yyvstop + 178,
yycrank + 183, yysvec + 13, yyvstop + 181,
yycrank + 182, yysvec + 13, yyvstop + 183,
yycrank + 0, yysvec + 13, yyvstop + 185,
yycrank + 172, yysvec + 13, yyvstop + 189,
yycrank + 181, yysvec + 13, yyvstop + 191,
yycrank + 0, yysvec + 13, yyvstop + 193,
yycrank + 0, yysvec + 13, yyvstop + 196,
yycrank + 189, 0, 0,
89
yycrank + 195, 0, 0,
yycrank + 0, yysvec + 13, yyvstop + 199,
yycrank + 183, yysvec + 13, yyvstop + 202,
yycrank + 0, yysvec + 13, yyvstop + 204,
yycrank + 0, yysvec + 13, yyvstop + 207,
yycrank + 0, 0, yyvstop + 210,
yycrank + 178, 0, 0,
yycrank + 186, yysvec + 13, yyvstop + 212,
yycrank + 204, 0, 0,
yycrank + 0, yysvec + 13, yyvstop + 214,
yycrank + 0, 0, yyvstop + 217,
0, 0, 0
};
struct yywork *yytop = yycrank + 423;
struct yysvf *yybgin = yysvec + 1;
char yymatch[] = {
00, 01, 01, 01, 01, 01, 01, 01,
01, 011, 012, 01, 01, 01, 01, 01,
01, 01, 01, 01, 01, 01, 01, 01,
01, 01, 01, 01, 01, 01, 01, 01,
011, 01, '"', 01, 01, 01, 01, 047,
01, 01, 01, '+', 01, '+', 01, 01,
'0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', 01, 01, 01, 01, 01, 01,
01, 'A', 'A', 'A', 'D', 'D', 'A', 'D',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 01, 01, 01, 01, 'A',
01, 'A', 'A', 'A', 'D', 'D', 'A', 'D',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
'A', 'A', 'A', 01, 01, 01, 01, 01,
0
};
char yyextra[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
};
#ifndef lint
static char ncform_sccsid[] = "@(#)ncform 1.6 88/02/08 SMI"; /* from
S5R2 1.2 */
#endif
int yylineno = 1;
# define YYU(x) x
# define NLSTATE yyprevious=YYNEWLINE
char yytext[YYLMAX];
struct yysvf *yylstate[YYLMAX], **yylsp, **yyolsp;
char yysbuf[YYLMAX];
char *yysptr = yysbuf;
int *yyfnd;
extern struct yysvf *yyestate;
int yyprevious = YYNEWLINE;
yylook()
90
{
// register struct yysvf *yystate, **lsp;
struct yysvf *yystate, **lsp;
// register struct yywork *yyt;
struct yywork *yyt;
struct yysvf *yyz;
int yych, yyfirst;
struct yywork *yyr;
# ifdef LEXDEBUG
int debug;
# endif
char *yylastch;
/* start off machines */
# ifdef LEXDEBUG
debug = 0;
# endif
yyfirst = 1;
if (!yymorfg)
yylastch = yytext;
else {
yymorfg = 0;
yylastch = yytext + yyleng;
}
for (;;) {
lsp = yylstate;
yyestate = yystate = yybgin;
if (yyprevious == YYNEWLINE)
yystate++;
for (;;) {
yyt = yystate->yystoff;
if (yyt == yycrank && !yyfirst) { /* may
not be any transitions */
yyz = yystate->yyother;
if (yyz == 0)
break;
if (yyz->yystoff == yycrank)
break;
}
*yylastch++ = yych = input();
yyfirst = 0;
tryagain:
yyr = yyt;
if ((int) yyt > (int) yycrank) {
yyt = yyr + yych;
if (yyt <= yytop && yyt->verify + yysvec
== yystate) {
if (yyt->advance + yysvec ==
YYLERR) { /* error transitions */
unput(*--yylastch);
break;
}
*lsp++ = yystate = yyt->advance
+ yysvec;
goto contin;
}
}
# ifdef YYOPTIM
else if ((int) yyt < (int) yycrank) { /* r <
yycrank */
91
yyt = yyr = yycrank + (yycrank - yyt);
# ifdef LEXDEBUG
if (debug)
fprintf(yyout, "compressed
staten");
# endif
yyt = yyt + yych;
if (yyt <= yytop && yyt->verify + yysvec
== yystate) {
if (yyt->advance + yysvec ==
YYLERR) { /* error transitions */
unput(*--yylastch);
break;
}
*lsp++ = yystate = yyt->advance
+ yysvec;
goto contin;
}
yyt = yyr + YYU(yymatch[yych]);
# ifdef LEXDEBUG
if (debug) {
fprintf(yyout, "try fall back
character ");
allprint(YYU(yymatch[yych]));
putchar('n');
}
# endif
if (yyt <= yytop && yyt->verify + yysvec
== yystate) {
if (yyt->advance + yysvec ==
YYLERR) { /* error transition */
unput(*--yylastch);
break;
}
*lsp++ = yystate = yyt->advance
+ yysvec;
goto contin;
}
}
if ((yystate = yystate->yyother)
&& (yyt = yystate->yystoff) != yycrank)
{
# ifdef LEXDEBUG
if (debug)
fprintf(yyout, "fall back to
state %dn", yystate - yysvec - 1);
# endif
goto tryagain;
}
# endif
else {
unput(*--yylastch);
break;
}
contin:
# ifdef LEXDEBUG
if (debug) {
fprintf(yyout, "state %d char ", yystate
- yysvec - 1);
allprint(yych);
putchar('n');
92
}
# endif
;
}
# ifdef LEXDEBUG
if (debug) {
fprintf(yyout, "stopped at %d with ", *(lsp -
1) - yysvec - 1);
allprint(yych);
putchar('n');
}
# endif
while (lsp-- > yylstate) {
*yylastch-- = 0;
if (*lsp != 0 && (yyfnd = (*lsp)->yystops) &&
*yyfnd > 0) {
yyolsp = lsp;
if (yyextra[*yyfnd]) { /* must backup */
while (yyback((*lsp)->yystops, -
*yyfnd) != 1 && lsp > yylstate) {
lsp--;
unput(*yylastch--);
}
}
yyprevious = YYU(*yylastch);
yylsp = lsp;
yyleng = yylastch - yytext + 1;
yytext[yyleng] = 0;
# ifdef LEXDEBUG
if (debug) {
fprintf(yyout, "nmatch ");
sprint(yytext);
fprintf(yyout, " action %dn",
*yyfnd);
}
# endif
return (*yyfnd++);
}
unput(*yylastch);
}
if (yytext[0] == 0 /* && feof(yyin) */ ) {
yysptr = yysbuf;
return (0);
}
yyprevious = yytext[0] = input();
if (yyprevious > 0)
output(yyprevious);
yylastch = yytext;
# ifdef LEXDEBUG
if (debug)
putchar('n');
# endif
}
}
yyback(p, m)
int *p;
{
if (p == 0)
return (0);
while (*p) {
93
if (*p++ == m)
return (1);
}
return (0);
}
/* the following are only used in the lex library */
yyinput()
{
return (input());
}
yyoutput(int c)
{
output(c);
}
yyunput(int c)
{
unput(c);
}
/*
** objects.c
** DRVS-All opcodes are here
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "objects.h"
#include "hash.h"
#include "inout.h"
#include "table.h"
#include "dfn.h"
#define tonumber(o) ((tag(o) != T_NUMBER) && (dfn_tonumber(o) != 0))
#define tostring(o) ((tag(o) != T_STRING) && (dfn_tostring(o) != 0))
#ifndef MAXSTACK
#define MAXSTACK 256
#endif
static Object stack[MAXSTACK] = {
{T_MARK,
{NULL}}
};
static Object *top = stack + 1, *base = stack + 1;
/*
*/
static char *dfn_strconc(char *l, char *r) {
char *s = calloc(strlen(l) + strlen(r) + 2, sizeof (char));
if (s == NULL) {
dfn_error("not enough memory");
return NULL;
}
*s++ = 0;
94
return strcat(strcpy(s, l), r);
}
/*
*/
char *dfn_strdup(char *l) {
char *s = calloc(strlen(l) + 2, sizeof (char));
if (s == NULL) {
dfn_error("not enough memory");
return NULL;
}
*s++ = 0; /* create mark space */
return strcpy(s, l);
}
/*
*/
static int dfn_tonumber(Object * obj) {
char *ptr;
if (tag(obj) != T_STRING) {
dfn_reportbug("unexpected type at conversion to number");
return 1;
}
nvalue(obj) = strtod(svalue(obj), &ptr);
if (*ptr) {
dfn_reportbug("string to number convertion failed");
return 2;
}
tag(obj) = T_NUMBER;
return 0;
}
/*
*/
static Object *dfn_convtonumber(Object * obj) {
static Object cvt;
if (tag(obj) == T_NUMBER) {
cvt = *obj;
return &cvt;
}
tag(&cvt) = T_NIL;
if (tag(obj) == T_STRING) {
char *ptr;
nvalue(&cvt) = strtod(svalue(obj), &ptr);
if (*ptr == 0)
tag(&cvt) = T_NUMBER;
}
return &cvt;
}
/*
*/
static int dfn_tostring(Object * obj) {
static char s[256];
if (tag(obj) != T_NUMBER) {
dfn_reportbug("unexpected type at conversion to string");
return 1;
}
if ((int) nvalue(obj) == nvalue(obj))
95
sprintf(s, "%d", (int) nvalue(obj));
else
sprintf(s, "%g", nvalue(obj));
svalue(obj) = dfn_createstring(dfn_strdup(s));
if (svalue(obj) == NULL)
return 1;
tag(obj) = T_STRING;
return 0;
}
/*
*/
int dfn_execute(Byte * pc) {
while (1) {
switch ((OpCode) * pc++) {
case NOP:
break;
case PUSHNIL:
tag(top++) = T_NIL;
break;
case PUSH0:
tag(top) = T_NUMBER;
nvalue(top++) = 0;
break;
case PUSH1:
tag(top) = T_NUMBER;
nvalue(top++) = 1;
break;
case PUSH2:
tag(top) = T_NUMBER;
nvalue(top++) = 2;
break;
case PUSHBYTE:
tag(top) = T_NUMBER;
nvalue(top++) = *pc++;
break;
case PUSHWORD:
tag(top) = T_NUMBER;
nvalue(top++) = *((Word *) (pc));
pc += sizeof (Word);
break;
case PUSHFLOAT:
tag(top) = T_NUMBER;
nvalue(top++) = *((float *) (pc));
pc += sizeof (float);
break;
case PUSHSTRING:
{
int w = *((Word *) (pc));
pc += sizeof (Word);
tag(top) = T_STRING;
svalue(top++) = dfn_constant[w];
}
break;
case PUSHLOCAL0:
96
*top++ = *(base + 0);
break;
case PUSHLOCAL1:
*top++ = *(base + 1);
break;
case PUSHLOCAL2:
*top++ = *(base + 2);
break;
case PUSHLOCAL3:
*top++ = *(base + 3);
break;
case PUSHLOCAL4:
*top++ = *(base + 4);
break;
case PUSHLOCAL5:
*top++ = *(base + 5);
break;
case PUSHLOCAL6:
*top++ = *(base + 6);
break;
case PUSHLOCAL7:
*top++ = *(base + 7);
break;
case PUSHLOCAL8:
*top++ = *(base + 8);
break;
case PUSHLOCAL9:
*top++ = *(base + 9);
break;
case PUSHLOCAL:
*top++ = *(base + (*pc++));
break;
case PUSHGLOBAL:
*top++ = s_object(*((Word *) (pc)));
pc += sizeof (Word);
break;
case PUSHINDEXED:
--top;
if (tag(top - 1) != T_ARRAY) {
dfn_reportbug("indexed expression not a table");
return 1;
}
{
Object *h = dfn_hashdefine(avalue(top - 1), top);
if (h == NULL)
return 1;
*(top - 1) = *h;
}
break;
case PUSHMARK:
tag(top++) = T_MARK;
break;
case PUSHOBJECT:
*top = *(top - 3);
top++;
break;
97
case STORELOCAL0:
*(base + 0) = *(--top);
break;
case STORELOCAL1:
*(base + 1) = *(--top);
break;
case STORELOCAL2:
*(base + 2) = *(--top);
break;
case STORELOCAL3:
*(base + 3) = *(--top);
break;
case STORELOCAL4:
*(base + 4) = *(--top);
break;
case STORELOCAL5:
*(base + 5) = *(--top);
break;
case STORELOCAL6:
*(base + 6) = *(--top);
break;
case STORELOCAL7:
*(base + 7) = *(--top);
break;
case STORELOCAL8:
*(base + 8) = *(--top);
break;
case STORELOCAL9:
*(base + 9) = *(--top);
break;
case STORELOCAL:
*(base + (*pc++)) = *(--top);
break;
case STOREGLOBAL:
s_object(*((Word *) (pc))) = *(--top);
pc += sizeof (Word);
break;
case STOREINDEXED0:
if (tag(top - 3) != T_ARRAY) {
dfn_reportbug("indexed expression not a table");
return 1;
}
{
Object *h = dfn_hashdefine(avalue(top - 3), top - 2);
if (h == NULL)
return 1;
*h = *(top - 1);
}
top -= 3;
break;
case STOREINDEXED:
{
int n = *pc++;
if (tag(top - 3 - n) != T_ARRAY) {
dfn_reportbug("indexed expression not a table");
return 1;
98
}
{
Object *h = dfn_hashdefine(avalue(top - 3 - n),
top - 2 - n);
if (h == NULL)
return 1;
*h = *(top - 1);
}
--top;
}
break;
case STOREFIELD:
if (tag(top - 3) != T_ARRAY) {
dfn_error("internal error - table expected");
return 1;
}
*(dfn_hashdefine(avalue(top - 3), top - 2)) = *(top -
1);
top -= 2;
break;
case ADJUST:
{
Object *newtop = base + *(pc++);
if (top != newtop) {
while (top < newtop)
tag(top++) = T_NIL;
top = newtop;
}
}
break;
case CREATEARRAY:
if (tag(top - 1) == T_NIL)
nvalue(top - 1) = 101;
else {
if (tonumber(top - 1))
return 1;
if (nvalue(top - 1) <= 0)
nvalue(top - 1) = 101;
}
avalue(top - 1) =
dfn_createarray(dfn_hashcreate(nvalue(top - 1)));
if (avalue(top - 1) == NULL)
return 1;
tag(top - 1) = T_ARRAY;
break;
case EQOP:
{
Object *l = top - 2;
Object *r = top - 1;
--top;
if (tag(l) != tag(r))
tag(top - 1) = T_NIL;
else {
switch (tag(l)) {
case T_NIL:
tag(top - 1) = T_NUMBER;
break;
99
case T_NUMBER:
tag(top - 1) = (nvalue(l) == nvalue(r)) ?
T_NUMBER : T_NIL;
break;
case T_ARRAY:
tag(top - 1) = (avalue(l) == avalue(r)) ?
T_NUMBER : T_NIL;
break;
case T_FUNCTION:
tag(top - 1) = (bvalue(l) == bvalue(r)) ?
T_NUMBER : T_NIL;
break;
case T_CFUNCTION:
tag(top - 1) = (fvalue(l) == fvalue(r)) ?
T_NUMBER : T_NIL;
break;
case T_USERDATA:
tag(top - 1) = (uvalue(l) == uvalue(r)) ?
T_NUMBER : T_NIL;
break;
case T_STRING:
tag(top - 1) =
(strcmp(svalue(l), svalue(r)) ==
0) ? T_NUMBER : T_NIL;
break;
case T_MARK:
return 1;
}
}
nvalue(top - 1) = 1;
}
break;
case LTOP:
{
Object *l = top - 2;
Object *r = top - 1;
--top;
if (tag(l) == T_NUMBER && tag(r) == T_NUMBER)
tag(top - 1) = (nvalue(l) < nvalue(r)) ? T_NUMBER
: T_NIL;
else {
if (tostring(l) || tostring(r))
return 1;
tag(top - 1) = (strcmp(svalue(l), svalue(r)) < 0)
? T_NUMBER : T_NIL;
}
nvalue(top - 1) = 1;
}
break;
case LEOP:
{
Object *l = top - 2;
Object *r = top - 1;
--top;
if (tag(l) == T_NUMBER && tag(r) == T_NUMBER)
tag(top - 1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER
: T_NIL;
else {
if (tostring(l) || tostring(r))
100
return 1;
tag(top - 1) = (strcmp(svalue(l), svalue(r)) <= 0)
? T_NUMBER : T_NIL;
}
nvalue(top - 1) = 1;
}
break;
case ADDOP:
{
Object *l = top - 2;
Object *r = top - 1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) += nvalue(r);
--top;
}
break;
case SUBOP:
{
Object *l = top - 2;
Object *r = top - 1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) -= nvalue(r);
--top;
}
break;
case MULTOP:
{
Object *l = top - 2;
Object *r = top - 1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) *= nvalue(r);
--top;
}
break;
case DIVOP:
{
Object *l = top - 2;
Object *r = top - 1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) /= nvalue(r);
--top;
}
break;
case CONCOP:
{
Object *l = top - 2;
Object *r = top - 1;
if (tostring(r) || tostring(l))
return 1;
svalue(l) = dfn_createstring(dfn_strconc(svalue(l),
svalue(r)));
if (svalue(l) == NULL)
101
return 1;
--top;
}
break;
case MINUSOP:
if (tonumber(top - 1))
return 1;
nvalue(top - 1) = -nvalue(top - 1);
break;
case NOTOP:
tag(top - 1) = tag(top - 1) == T_NIL ? T_NUMBER :
T_NIL;
break;
case ONTJMP:
{
int n = *((Word *) (pc));
pc += sizeof (Word);
if (tag(top - 1) != T_NIL)
pc += n;
}
break;
case ONFJMP:
{
int n = *((Word *) (pc));
pc += sizeof (Word);
if (tag(top - 1) == T_NIL)
pc += n;
}
break;
case JMP:
pc += *((Word *) (pc)) + sizeof (Word);
break;
case UPJMP:
pc -= *((Word *) (pc)) - sizeof (Word);
break;
case IFFJMP:
{
int n = *((Word *) (pc));
pc += sizeof (Word);
top--;
if (tag(top) == T_NIL)
pc += n;
}
break;
case IFFUPJMP:
{
int n = *((Word *) (pc));
pc += sizeof (Word);
top--;
if (tag(top) == T_NIL)
pc -= n;
}
break;
102
case POP:
--top;
break;
case CALLFUNC:
{
Byte *newpc;
Object *b = top - 1;
while (tag(b) != T_MARK)
b--;
if (tag(b - 1) == T_FUNCTION) {
dfn_debugline = 0;
newpc = bvalue(b - 1);
bvalue(b - 1) = pc;
nvalue(b) = (base - stack);
base = b + 1;
pc = newpc;
if (MAXSTACK - (base - stack) < STACKGAP) {
dfn_error("stack overflow");
return 1;
}
} else if (tag(b - 1) == T_CFUNCTION) {
int nparam;
dfn_debugline = 0;
nvalue(b) = (base - stack);
base = b + 1;
nparam = top - base;
(fvalue(b - 1)) ();
{
int i;
int nretval = top - base - nparam;
top = base - 2;
base = stack + (int) nvalue(base - 1);
for (i = 0; i < nretval; i++) {
*top = *(top + nparam + 2);
++top;
}
}
} else {
dfn_reportbug("call expression not a function");
return 1;
}
}
break;
case RETCODE:
{
int i;
int shift = *pc++;
int nretval = top - base - shift;
top = base - 2;
pc = bvalue(base - 2);
base = stack + (int) nvalue(base - 1);
for (i = 0; i < nretval; i++) {
*top = *(top + shift + 2);
++top;
}
}
break;
103
case HALT:
return 0;
case SETFUNCTION:
{
int file, func;
file = *((Word *) (pc));
pc += sizeof (Word);
func = *((Word *) (pc));
pc += sizeof (Word);
if (dfn_pushfunction(file, func))
return 1;
}
break;
case SETLINE:
dfn_debugline = *((Word *) (pc));
pc += sizeof (Word);
break;
case RESET:
dfn_popfunction();
break;
default:
dfn_error("internal error - opcode didn't match");
return 1;
}
}
}
/*
*/
void dfn_markstack(void) {
Object *o;
for (o = top - 1; o >= stack; o--)
dfn_markobject(o);
}
/*
*/
int dfn_execfile(char *filename) {
int x, y;
y = dfn_openfile(filename);
if (y)
return 1;
x=dfn_parse();
if( x ){
dfn_closefile();
return 1;
}
dfn_closefile();
return 0;
}
/*
*/
int dfn_dostring(char *string) {
if (dfn_openstring(string))
104
return 1;
if (dfn_parse())
return 1;
return 0;
}
/*
*/
int dfn_call(char *functionname, int nparam) {
static Byte startcode[] = {CALLFUNC, HALT};
int i;
Object func = s_object(dfn_findsymbol(functionname));
if (tag(&func) != T_FUNCTION)
return 1;
for (i = 1; i <= nparam; i++)
*(top - i + 2) = *(top - i);
top += 2;
tag(top - nparam - 1) = T_MARK;
*(top - nparam - 2) = func;
return (dfn_execute(startcode));
}
/*
*/
Object *dfn_getparam(int number) {
if (number <= 0 || number > top - base)
return NULL;
return (base + number - 1);
}
/*
*/
real dfn_getnumber(Object * object) {
if (tonumber(object))
return 0.0;
else
return (nvalue(object));
}
/*
*/
char *dfn_getstring(Object * object) {
if (tostring(object))
return NULL;
else
return (svalue(object));
}
/*
*/
char *dfn_copystring(Object * object) {
if (tostring(object))
return NULL;
else
return (strdup(svalue(object)));
}
/*
*/
dfn_CFunction dfn_getcfunction(Object * object) {
if (tag(object) != T_CFUNCTION)
105
return NULL;
else
return (fvalue(object));
}
/*
*/
void *dfn_getuserdata(Object * object) {
if (tag(object) != T_USERDATA)
return NULL;
else
return (uvalue(object));
}
/*
*/
Object *dfn_getfield(Object * object, char *field) {
if (tag(object) != T_ARRAY)
return NULL;
else {
Object ref;
tag(&ref) = T_STRING;
svalue(&ref) = dfn_createstring(dfn_strdup(field));
return (dfn_hashdefine(avalue(object), &ref));
}
}
/*
*/
Object *dfn_getindexed(Object * object, float index) {
if (tag(object) != T_ARRAY)
return NULL;
else {
Object ref;
tag(&ref) = T_NUMBER;
nvalue(&ref) = index;
return (dfn_hashdefine(avalue(object), &ref));
}
}
/*
*/
Object *dfn_getglobal(char *name) {
int n = dfn_findsymbol(name);
if (n < 0)
return NULL;
return &s_object(n);
}
/*
*/
Object *dfn_pop(void) {
if (top <= base)
return NULL;
top--;
return top;
}
/*
*/
int dfn_pushnil(void) {
106
if ((top - stack) >= MAXSTACK - 1) {
dfn_error("stack overflow");
return 1;
}
tag(top) = T_NIL;
return 0;
}
/*
*/
int dfn_pushnumber(real n) {
if ((top - stack) >= MAXSTACK - 1) {
dfn_error("stack overflow");
return 1;
}
tag(top) = T_NUMBER;
nvalue(top++) = n;
return 0;
}
/*
*/
int dfn_pushstring(char *s) {
if ((top - stack) >= MAXSTACK - 1) {
dfn_error("stack overflow");
return 1;
}
tag(top) = T_STRING;
svalue(top++) = dfn_createstring(dfn_strdup(s));
return 0;
}
/*
*/
int dfn_pushcfunction(dfn_CFunction fn) {
if ((top - stack) >= MAXSTACK - 1) {
dfn_error("stack overflow");
return 1;
}
tag(top) = T_CFUNCTION;
fvalue(top++) = fn;
return 0;
}
/*
*/
int dfn_pushuserdata(void *u) {
if ((top - stack) >= MAXSTACK - 1) {
dfn_error("stack overflow");
return 1;
}
tag(top) = T_USERDATA;
uvalue(top++) = u;
return 0;
}
/*
*/
int dfn_pushobject(Object * o) {
if ((top - stack) >= MAXSTACK - 1) {
dfn_error("stack overflow");
107
return 1;
}
*top++ = *o;
return 0;
}
/*
*/
int dfn_globalref(char *name) {
int n = dfn_findsymbol(name);
if (n < 0)
return 1;
if (tag(top - 1) == T_MARK)
return 1;
s_object(n) = *(--top);
return 0;
}
/*
*/
int dfn_storefield(dfn_Object object, char *field) {
if (tag(object) != T_ARRAY)
return 1;
else {
Object ref, *h;
tag(&ref) = T_STRING;
svalue(&ref) = dfn_createstring(dfn_strdup(field));
h = dfn_hashdefine(avalue(object), &ref);
if (h == NULL)
return 1;
if (tag(top - 1) == T_MARK)
return 1;
*h = *(--top);
}
return 0;
}
/*
*/
int dfn_storeindexed(dfn_Object object, float index) {
if (tag(object) != T_ARRAY)
return 1;
else {
Object ref, *h;
tag(&ref) = T_NUMBER;
nvalue(&ref) = index;
h = dfn_hashdefine(avalue(object), &ref);
if (h == NULL)
return 1;
if (tag(top - 1) == T_MARK)
return 1;
*h = *(--top);
}
return 0;
}
/*
*/
int dfn_isnil(Object * object) {
return (object != NULL && tag(object) == T_NIL);
}
108
/*
*/
int dfn_isnumber(Object * object) {
return (object != NULL && tag(object) == T_NUMBER);
}
/*
*/
int dfn_isstring(Object * object) {
return (object != NULL && tag(object) == T_STRING);
}
/*
*/
int dfn_istable(Object * object) {
return (object != NULL && tag(object) == T_ARRAY);
}
/*
*/
int dfn_iscfunction(Object * object) {
return (object != NULL && tag(object) == T_CFUNCTION);
}
/*
*/
int dfn_isuserdata(Object * object) {
return (object != NULL && tag(object) == T_USERDATA);
}
/*
*/
void dfn_type(void) {
Object *o = dfn_getparam(1);
dfn_pushstring(dfn_constant[tag(o)]);
}
/*
*/
void dfn_obj2number(void) {
Object *o = dfn_getparam(1);
dfn_pushobject(dfn_convtonumber(o));
}
/*
*/
void dfn_print(void) {
int i = 1;
void *obj;
while ((obj = dfn_getparam(i++)) != NULL) {
if (dfn_isnumber(obj))
printf("%gn", dfn_getnumber(obj));
else if (dfn_isstring(obj))
printf("%sn", dfn_getstring(obj));
else if (dfn_iscfunction(obj))
printf("function: %pn", dfn_getcfunction(obj));
else if (dfn_isuserdata(obj))
printf("usertype: %pn", dfn_getuserdata(obj));
else if (dfn_istable(obj))
printf("table: %pn", obj);
109
else if (dfn_isnil(obj))
printf("nulln");
else
printf("print: invalid parametern");
}
}
/*
** objects.h
*/
#ifndef objects_h
#define objects_h
#ifndef STACKGAP
#define STACKGAP 128
#endif
#ifndef real
#define real float
#endif
typedef unsigned char Byte;
typedef unsigned short Word;
typedef enum {
NOP,
PUSHNIL,
PUSH0, PUSH1, PUSH2,
PUSHBYTE,
PUSHWORD,
PUSHFLOAT,
PUSHSTRING,
PUSHLOCAL0, PUSHLOCAL1, PUSHLOCAL2, PUSHLOCAL3, PUSHLOCAL4,
PUSHLOCAL5, PUSHLOCAL6, PUSHLOCAL7, PUSHLOCAL8, PUSHLOCAL9,
PUSHLOCAL,
PUSHGLOBAL,
PUSHINDEXED,
PUSHMARK,
PUSHOBJECT,
STORELOCAL0, STORELOCAL1, STORELOCAL2, STORELOCAL3,
STORELOCAL4,
STORELOCAL5, STORELOCAL6, STORELOCAL7, STORELOCAL8,
STORELOCAL9,
STORELOCAL,
STOREGLOBAL,
STOREINDEXED0,
STOREINDEXED,
STOREFIELD,
ADJUST,
CREATEARRAY,
EQOP,
LTOP,
LEOP,
ADDOP,
SUBOP,
MULTOP,
DIVOP,
CONCOP,
110
MINUSOP,
NOTOP,
ONTJMP,
ONFJMP,
JMP,
UPJMP,
IFFJMP,
IFFUPJMP,
POP,
CALLFUNC,
RETCODE,
HALT,
SETFUNCTION,
SETLINE,
RESET
} OpCode;
typedef enum {
T_MARK,
T_NIL,
T_NUMBER,
T_STRING,
T_ARRAY,
T_FUNCTION,
T_CFUNCTION,
T_USERDATA
} Type;
typedef void (*Cfunction) (void);
typedef int (*Input) (void);
typedef void (*Unput) (int);
typedef union {
Cfunction f;
real n;
char *s;
Byte *b;
struct Hash *a;
void *u;
} Value;
typedef struct Object {
Type tag;
Value value;
} Object;
typedef struct {
char *name;
Object object;
} Symbol;
/* Macros to access structure members */
#define tag(o) ((o)->tag)
#define nvalue(o) ((o)->value.n)
#define svalue(o) ((o)->value.s)
#define bvalue(o) ((o)->value.b)
#define avalue(o) ((o)->value.a)
#define fvalue(o) ((o)->value.f)
#define uvalue(o) ((o)->value.u)
/* Macros to access symbol table */
111
#define s_name(i) (dfn_table[i].name)
#define s_object(i) (dfn_table[i].object)
#define s_tag(i) (tag(&s_object(i)))
#define s_nvalue(i) (nvalue(&s_object(i)))
#define s_svalue(i) (svalue(&s_object(i)))
#define s_bvalue(i) (bvalue(&s_object(i)))
#define s_avalue(i) (avalue(&s_object(i)))
#define s_fvalue(i) (fvalue(&s_object(i)))
#define s_uvalue(i) (uvalue(&s_object(i)))
/* Exported functions */
int dfn_execute(Byte * pc);
void dfn_markstack(void);
char *dfn_strdup(char *l);
void dfn_setinput(Input fn); /* from "dfn.lex" module */
void dfn_setunput(Unput fn); /* from "dfn.lex" module */
char *dfn_lasttext(void); /* from "dfn.lex" module */
int dfn_parse(void); /* from "dfn.stx" module */
void dfn_type(void);
void dfn_obj2number(void);
void dfn_print(void);
#endif
/*
** table.c
*/
#include <stdlib.h>
#include <string.h>
#include "objects.h"
#include "hash.h"
#include "inout.h"
#include "table.h"
#include "dfn.h"
#define streq(s1,s2) (strcmp(s1,s2)==0)
#ifndef MAXSYMBOL
#define MAXSYMBOL 512
#endif
static Symbol tablebuffer[MAXSYMBOL] = {
{"type", {T_CFUNCTION, {dfn_type}}},
{"strtonum", {T_CFUNCTION, {dfn_obj2number}}},
{"next", {T_CFUNCTION, {dfn_next}}},
{"nextvar", {T_CFUNCTION, {dfn_nextvar}}},
{"print", {T_CFUNCTION, {dfn_print}}}
};
Symbol *dfn_table = tablebuffer;
Word dfn_ntable = 5;
#ifndef MAXCONSTANT
#define MAXCONSTANT 256
#endif
static char *constantbuffer[MAXCONSTANT] = { "mark", "nil", "number",
112
"string", "table",
"function", "cfunction"
};
char **dfn_constant = constantbuffer;
Word dfn_nconstant = T_CFUNCTION + 1;
#ifndef MAXSTRING
#define MAXSTRING 512
#endif
static char *stringbuffer[MAXSTRING];
char **dfn_string = stringbuffer;
Word dfn_nstring = 0;
#ifndef MAXARRAY
#define MAXARRAY 512
#endif
static Hash *arraybuffer[MAXARRAY];
Hash **dfn_array = arraybuffer;
Word dfn_narray = 0;
#define MAXFILE 20
char *dfn_file[MAXFILE];
int dfn_nfile;
/*
*/
int dfn_findsymbol(char *s)
{
int i;
for (i = 0; i < dfn_ntable; i++)
if (streq(s, s_name(i)))
return i;
if (dfn_ntable >= MAXSYMBOL - 1) {
dfn_error("symbol table overflow");
return -1;
}
s_name(dfn_ntable) = strdup(s);
if (s_name(dfn_ntable) == NULL) {
dfn_error("not enough memory");
return -1;
}
s_tag(dfn_ntable++) = T_NIL;
return (dfn_ntable - 1);
}
/*
**
*/
int dfn_findenclosedconstant(char *s)
{
int i, j, l = strlen(s);
char *c = calloc(l, sizeof(char));
c++;
/* scape characters */
for (i = 1, j = 0; i < l - 1; i++) {
if (s[i] == '') {
113
switch (s[++i]) {
case 'n':
c[j++] = 'n';
break;
case 't':
c[j++] = 't';
break;
case 'r':
c[j++] = 'r';
break;
default:
c[j++] = '';
c[j++] = c[i];
break;
}
} else
c[j++] = s[i];
}
c[j++] = 0;
for (i = 0; i < dfn_nconstant; i++)
if (streq(c, dfn_constant[i])) {
free(c - 1);
return i;
}
if (dfn_nconstant >= MAXCONSTANT - 1) {
dfn_error("dfn: constant string table overflow");
return -1;
}
dfn_constant[dfn_nconstant++] = c;
return (dfn_nconstant - 1);
}
/*
*/
int dfn_findconstant(char *s)
{
int i;
for (i = 0; i < dfn_nconstant; i++)
if (streq(s, dfn_constant[i]))
return i;
if (dfn_nconstant >= MAXCONSTANT - 1) {
dfn_error("dfn: constant string table overflow");
return -1;
}
{
char *c = calloc(strlen(s) + 2, sizeof(char));
c++;
dfn_constant[dfn_nconstant++] = strcpy(c, s);
}
return (dfn_nconstant - 1);
}
/*
*/
void dfn_markobject(Object * o)
{
if (tag(o) == T_STRING)
dfn_markstring(svalue(o)) = 1;
else if (tag(o) == T_ARRAY && markarray(avalue(o)) == 0)
114
dfn_hashmark(avalue(o));
}
/*
*/
static void dfn_marktable(void)
{
int i;
for (i = 0; i < dfn_ntable; i++)
dfn_markobject(&s_object(i));
}
/*
*/
static void dfn_pack(void)
{
dfn_markstack();
dfn_marktable();
{
int i, j;
for (i = j = 0; i < dfn_nstring; i++)
if (dfn_markstring(dfn_string[i]) == 1) {
dfn_string[j++] = dfn_string[i];
dfn_markstring(dfn_string[i]) = 0;
} else {
free(dfn_string[i] - 1);
}
dfn_nstring = j;
}
{
int i, j;
for (i = j = 0; i < dfn_narray; i++)
if (markarray(dfn_array[i]) == 1) {
dfn_array[j++] = dfn_array[i];
markarray(dfn_array[i]) = 0;
} else {
dfn_hashdelete(dfn_array[i]);
}
dfn_narray = j;
}
}
/*
*/
char *dfn_createstring(char *s)
{
if (s == NULL)
return NULL;
if (dfn_nstring >= MAXSTRING - 1) {
dfn_pack();
if (dfn_nstring >= MAXSTRING - 1) {
dfn_error("string table overflow");
return NULL;
}
}
dfn_string[dfn_nstring++] = s;
return s;
}
115
/*
*/
void *dfn_createarray(void *a)
{
if (a == NULL)
return NULL;
if (dfn_narray >= MAXARRAY - 1) {
dfn_pack();
if (dfn_narray >= MAXARRAY - 1) {
dfn_error("indexed table overflow");
return NULL;
}
}
dfn_array[dfn_narray++] = a;
return a;
}
/*
*/
int dfn_addfile(char *fn)
{
if (dfn_nfile >= MAXFILE - 1) {
dfn_error("too many files");
return 1;
}
if ((dfn_file[dfn_nfile++] = strdup(fn)) == NULL) {
dfn_error("not enough memory");
return 1;
}
return 0;
}
/*
*/
char *dfn_filename(void)
{
return dfn_file[dfn_nfile - 1];
}
/*
*/
void dfn_nextvar(void)
{
int index;
Object *o = dfn_getparam(1);
if (o == NULL) {
dfn_error("too few arguments to function `nextvar'");
return;
}
if (dfn_getparam(2) != NULL) {
dfn_error("too many arguments to function `nextvar'");
return;
}
if (tag(o) == T_NIL) {
index = 0;
} else if (tag(o) != T_STRING) {
dfn_error("incorrect argument to function `nextvar'");
return;
116
} else {
for (index = 0; index < dfn_ntable; index++)
if (streq(s_name(index), svalue(o)))
break;
if (index == dfn_ntable) {
dfn_error("name not found in function
`nextvar'");
return;
}
index++;
while (index < dfn_ntable - 1 && tag(&s_object(index))
== T_NIL)
index++;
if (index == dfn_ntable - 1) {
dfn_pushnil();
dfn_pushnil();
return;
}
}
{
Object name;
tag(&name) = T_STRING;
svalue(&name) =
dfn_createstring(dfn_strdup(s_name(index)));
if (dfn_pushobject(&name))
return;
if (dfn_pushobject(&s_object(index)))
return;
}
}
/*
** table.c
*/
#ifndef table_h
#define table_h
extern Symbol *dfn_table;
extern Word dfn_ntable;
extern char **dfn_constant;
extern Word dfn_nconstant;
extern char **dfn_string;
extern Word dfn_nstring;
extern Hash **dfn_array;
extern Word dfn_narray;
extern char *dfn_file[];
extern int dfn_nfile;
#define dfn_markstring(s) (*((s)-1))
int dfn_findsymbol(char *s);
117
int dfn_findenclosedconstant(char *s);
int dfn_findconstant(char *s);
void dfn_markobject(Object * o);
char *dfn_createstring(char *s);
void *dfn_createarray(void *a);
int dfn_addfile(char *fn);
char *dfn_filename(void);
void dfn_nextvar(void);
#endif
/*
* y_tab.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "objects.h"
#include "hash.h"
#include "inout.h"
#include "table.h"
#include "dfn.h"
#ifndef ALIGNMENT
#define ALIGNMENT (sizeof(void *))
#endif
#ifndef MAXCODE
#define MAXCODE 1024
#endif
static long buffer[MAXCODE];
static Byte *code = (Byte *) buffer;
static long mainbuffer[MAXCODE];
static Byte *maincode = (Byte *) mainbuffer;
static Byte *basepc;
static Byte *pc;
#define MAXVAR 32
static long varbuffer[MAXVAR];
static Byte nvarbuffer = 0; /* number of variables at a list
*/
static Word localvar[STACKGAP];
static Byte nlocalvar = 0; /* number of local variables */
static int ntemp; /* number of temporary
var into stack */
static int err; /* flag to indicate error
*/
/* Internal functions */
#define align(n) align_n(sizeof(n))
static void code_byte(Byte c)
{
if (pc - basepc > MAXCODE - 1) {
dfn_error("code buffer overflow");
err = 1;
118
}
*pc++ = c;
}
static void code_word(Word n)
{
if (pc - basepc > MAXCODE - sizeof(Word)) {
dfn_error("code buffer overflow");
err = 1;
}
*((Word *) pc) = n;
pc += sizeof(Word);
}
static void code_float(float n)
{
if (pc - basepc > MAXCODE - sizeof(float)) {
dfn_error("code buffer overflow");
err = 1;
}
*((float *) pc) = n;
pc += sizeof(float);
}
static void incr_ntemp(void)
{
if (ntemp + nlocalvar + MAXVAR + 1 < STACKGAP)
ntemp++;
else {
dfn_error("stack overflow");
err = 1;
}
}
static void incr_nlocalvar(void)
{
if (ntemp + nlocalvar + MAXVAR + 1 < STACKGAP)
nlocalvar++;
else {
dfn_error("too many local variables or expression too
complicate");
err = 1;
}
}
static void incr_nvarbuffer(void)
{
if (nvarbuffer < MAXVAR - 1)
nvarbuffer++;
else {
dfn_error("variable buffer overflow");
err = 1;
}
}
static void align_n(unsigned size)
{
if (size > ALIGNMENT)
size = ALIGNMENT;
while (((pc + 1 - code) % size) != 0) /* +1 to include BYTECODE
*/
119
code_byte(NOP);
}
static void code_number(float f)
{
int i = f;
if (f == i) { /* f has an integer value
*/
if (i <= 2)
code_byte(PUSH0 + i);
else if (i <= 255) {
code_byte(PUSHBYTE);
code_byte(i);
} else {
align(Word);
code_byte(PUSHWORD);
code_word(i);
}
} else {
align(float);
code_byte(PUSHFLOAT);
code_float(f);
}
incr_ntemp();
}
typedef union {
int vInt;
long vLong;
float vFloat;
Word vWord;
Byte *pByte;
} YYSTYPE;
#define NIL 257
#define IF 258
#define THEN 259
#define ELSE 260
#define ELSEIF 261
#define WHILE 262
#define DO 263
#define REPEAT 264
#define UNTIL 265
#define END 266
#define RETURN 267
#define LOCAL 268
#define NUMBER 269
#define FUNCTION 270
#define NAME 271
#define STRING 272
#define DEBUG 273
#define NOT 274
#define AND 275
#define OR 276
#define NE 277
#define LE 278
#define GE 279
#define CONC 280
#define UNARY 281
#define ENDWHILE 300
#define ENDIF 301
120
#define yyclearin yychar = -1
#define yyerrok yyerrflag = 0
extern int yychar;
extern int yyerrflag;
#ifndef YYMAXDEPTH
#define YYMAXDEPTH 150
#endif
YYSTYPE yylval, yyval;
# define YYERRCODE 256
/*
** Search a local name and if find return its index. If do not find
return -1
*/
static int dfn_localname(Word n)
{
int i;
for (i = nlocalvar - 1; i >= 0; i--)
if (n == localvar[i])
return i; /* local var */
return -1; /* global var */
}
/*
** Push a variable given a number. If number is positive, push global
variable
** indexed by (number -1). If negative, push local indexed by
ABS(number)-1.
** Otherwise, if zero, push indexed variable (record).
*/
static void dfn_pushvar(long number)
{
if (number > 0) { /* global var */
align(Word);
code_byte(PUSHGLOBAL);
code_word(number - 1);
incr_ntemp();
} else if (number < 0) { /* local var */
number = (-number) - 1;
if (number < 10)
code_byte(PUSHLOCAL0 + number);
else {
code_byte(PUSHLOCAL);
code_byte(number);
}
incr_ntemp();
} else {
code_byte(PUSHINDEXED);
ntemp--;
}
}
static void dfn_codeadjust(int n)
{
code_byte(ADJUST);
121
code_byte(n + nlocalvar);
}
static void dfn_codestore(int i)
{
if (varbuffer[i] > 0) { /* global var */
align(Word);
code_byte(STOREGLOBAL);
code_word(varbuffer[i] - 1);
} else if (varbuffer[i] < 0) { /* local var */
int number = (-varbuffer[i]) - 1;
if (number < 10)
code_byte(STORELOCAL0 + number);
else {
code_byte(STORELOCAL);
code_byte(number);
}
} else { /* indexed var */
int j;
int upper = 0; /* number of indexed
variables upper */
int param; /* number of
itens until indexed expression */
for (j = i + 1; j < nvarbuffer; j++)
if (varbuffer[j] == 0)
upper++;
param = upper * 2 + i;
if (param == 0)
code_byte(STOREINDEXED0);
else {
code_byte(STOREINDEXED);
code_byte(param);
}
}
}
void yyerror(char *s)
{
static char msg[256];
sprintf(msg, "%s near "%s" at line %d in file "%s"",
s, dfn_lasttext(), dfn_linenumber,
dfn_filename());
dfn_error(msg);
err = 1;
}
int yywrap(void)
{
return 1;
}
/*
** Parse DFN Languace code and execute global statement.
** Return 0 on success or 1 on error.
*/
int dfn_parse(void)
{
Byte *initcode = maincode;
err = 0;
122
if (yyparse() || (err == 1))
return 1;
*maincode++ = HALT;
if (dfn_execute(initcode))
return 1;
maincode = initcode;
return 0;
}
int yyexca[] = {
-1, 1,
0, -1,
-2, 2,
-1, 19,
40, 65,
91, 95,
46, 97,
-2, 92,
-1, 29,
40, 65,
91, 95,
46, 97,
-2, 51,
-1, 70,
275, 33,
276, 33,
61, 33,
277, 33,
62, 33,
60, 33,
278, 33,
279, 33,
280, 33,
43, 33,
45, 33,
42, 33,
47, 33,
-2, 68,
-1, 71,
91, 95,
46, 97,
-2, 93,
-1, 102,
260, 27,
261, 27,
265, 27,
266, 27,
267, 27,
-2, 11,
-1, 117,
93, 85,
-2, 87,
-1, 122,
267, 30,
123
-2, 29,
-1, 145,
275, 33,
276, 33,
61, 33,
277, 33,
62, 33,
60, 33,
278, 33,
279, 33,
280, 33,
43, 33,
45, 33,
42, 33,
47, 33,
-2, 70,
};
# define YYNPROD 105
# define YYLAST 318
int yyact[] = {
54, 52, 136, 53, 13, 55, 54, 52, 14, 53,
15, 55, 5, 166, 18, 6, 129, 21, 47, 46,
48, 107, 104, 97, 47, 46, 48, 54, 52, 80,
53, 21, 55, 54, 52, 40, 53, 9, 55, 54,
52, 158, 53, 160, 55, 47, 46, 48, 159, 101,
81, 47, 46, 48, 10, 54, 52, 126, 53, 67,
55, 54, 52, 60, 53, 155, 55, 148, 149, 135,
147, 108, 150, 47, 46, 48, 73, 23, 75, 47,
46, 48, 7, 25, 38, 153, 26, 164, 27, 117,
61, 62, 74, 11, 76, 54, 24, 127, 65, 66,
55, 37, 154, 151, 103, 111, 72, 28, 93, 94,
82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
92, 116, 59, 77, 54, 52, 118, 53, 99, 55,
110, 95, 64, 44, 70, 109, 29, 33, 105, 106,
42, 112, 41, 165, 139, 19, 17, 152, 79, 123,
43, 119, 20, 114, 113, 98, 63, 144, 143, 122,
68, 39, 36, 130, 35, 120, 12, 8, 102, 125,
128, 141, 78, 69, 70, 71, 142, 131, 132, 140,
22, 124, 4, 3, 2, 121, 96, 138, 146, 137,
134, 157, 133, 115, 16, 1, 0, 0, 0, 0,
0, 0, 0, 156, 0, 0, 0, 0, 161, 0,
0, 0, 0, 162, 0, 0, 0, 168, 0, 172,
145, 163, 171, 0, 174, 0, 0, 0, 169, 156,
167, 170, 173, 57, 58, 49, 50, 51, 56, 57,
58, 49, 50, 51, 56, 175, 0, 0, 100, 0,
45, 0, 0, 0, 0, 70, 0, 0, 0, 0,
57, 58, 49, 50, 51, 56, 57, 58, 49, 50,
51, 56, 0, 0, 0, 0, 0, 56, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 57, 58,
49, 50, 51, 56, 0, 0, 49, 50, 51, 56,
32, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 30, 0, 21, 31, 0, 34
};
int yypact[] = {
-1000, -258, -1000, -1000, -1000, -234, -1000, 34, -254, -1000,
-1000, -1000, -1000, 43, -1000, -1000, 40, -1000, -236, -1000,
-1000, -1000, 93, -9, -1000, 43, 43, 43, 92, -1000,
124
-1000, -1000, -1000, -1000, 43, 43, -1000, 43, -240, 62,
31, -13, 48, 83, -242, -1000, 43, 43, 43, 43,
43, 43, 43, 43, 43, 43, 43, -1000, -1000, 90,
13, -1000, -1000, -248, 43, 19, -15, -216, -1000, 60,
-1000, -1000, -249, -1000, -1000, 43, -250, 43, 89, 61,
-1000, -1000, -3, -3, -3, -3, -3, -3, 53, 53,
-1000, -1000, 82, -1000, -1000, -1000, -2, -1000, 85, 13,
-1000, 43, -1000, -1000, 31, 43, -36, -1000, 56, 60,
-1000, -255, -1000, 43, 43, -1000, -269, -1000, -1000, -1000,
13, 34, -1000, 43, -1000, 13, -1000, -1000, -1000, -1000,
-193, 19, 19, -53, 59, -1000, -1000, -8, 58, 43,
-1000, -1000, -1000, -1000, -226, -1000, -218, -223, -1000, 43,
-1000, -269, 26, -1000, -1000, -1000, 13, -253, 43, -1000,
-1000, -1000, -42, -1000, 43, 43, -1000, 34, -1000, 13,
-1000, -1000, -1000, -1000, -193, -1000
};
int yypgo[] = {
0, 195, 50, 96, 71, 135, 194, 193, 192, 190,
189, 187, 136, 186, 184, 82, 54, 183, 182, 180,
172, 170, 59, 168, 167, 166, 63, 70, 164, 162,
137, 161, 160, 159, 158, 157, 156, 155, 154, 153,
152, 150, 149, 148, 69, 147, 144, 65, 143, 142,
140, 76, 138
};
int yyr1[] = {
0, 1, 14, 1, 1, 1, 19, 21, 17, 23,
23, 24, 15, 16, 16, 25, 28, 25, 29, 25,
25, 25, 25, 27, 27, 27, 32, 33, 22, 34,
35, 34, 2, 26, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 36, 3,
3, 3, 3, 3, 3, 3, 3, 38, 3, 39,
3, 37, 37, 41, 30, 40, 4, 4, 5, 42,
5, 20, 20, 43, 43, 13, 13, 7, 7, 8,
8, 9, 9, 45, 44, 10, 10, 46, 11, 48,
11, 47, 6, 6, 12, 49, 12, 50, 12, 31,
31, 51, 52, 51, 18
};
int yyr2[] = {
0, 0, 1, 9, 4, 4, 1, 1, 19, 0,
6, 1, 4, 0, 2, 17, 1, 17, 1, 13,
7, 3, 4, 0, 4, 15, 1, 1, 9, 0,
1, 9, 1, 3, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 5, 5, 1, 9,
9, 3, 3, 3, 3, 3, 5, 1, 11, 1,
11, 1, 2, 1, 11, 3, 1, 3, 3, 1,
9, 0, 2, 3, 7, 1, 3, 7, 7, 1,
3, 3, 7, 1, 9, 1, 3, 1, 5, 1,
9, 3, 3, 7, 3, 1, 11, 1, 9, 5,
9, 1, 1, 6, 3
};
int yychk[] = {
-1000, -1, -14, -17, -18, 270, 273, -15, -24, 271,
-16, 59, -25, 258, 262, 264, -6, -30, 268, -12,
125
-40, 271, -19, -26, -3, 40, 43, 45, 64, -12,
269, 272, 257, -30, 274, -28, -29, 61, 44, -31,
271, -49, -50, -41, 40, 259, 61, 60, 62, 277,
278, 279, 43, 45, 42, 47, 280, 275, 276, -3,
-26, -26, -26, -36, 40, -26, -26, -22, -32, -5,
-3, -12, 44, -51, 61, 91, 46, 40, -20, -43,
271, -2, -26, -26, -26, -26, -26, -26, -26, -26,
-26, -26, -26, -2, -2, 41, -13, 271, -37, -26,
263, 265, -23, 44, 271, -52, -26, 271, -4, -5,
41, 44, -22, -38, -39, -7, 123, 91, 41, -2,
-26, -15, -33, -42, -51, -26, 93, 41, -21, 271,
-2, -26, -26, -8, -9, -44, 271, -10, -11, -46,
-22, -2, -16, -34, -35, -3, -22, -27, 260, 261,
125, 44, -45, 93, 44, -47, -26, -2, 267, 266,
266, -22, -26, -44, 61, -48, 266, -4, 259, -26,
-47, -16, -2, -22, -2, -27
};
int yydef[] = {
1, -2, 11, 4, 5, 0, 104, 13, 0, 6,
3, 14, 12, 0, 16, 18, 0, 21, 0, -2,
63, 94, 0, 0, 33, 0, 0, 0, 48, -2,
52, 53, 54, 55, 0, 0, 26, 0, 0, 22,
101, 0, 0, 0, 71, 32, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 32, 32, 33,
0, 46, 47, 75, 61, 56, 0, 0, 9, 20,
-2, -2, 0, 99, 102, 0, 0, 66, 0, 72,
73, 26, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 57, 59, 34, 0, 76, 0, 62,
32, 0, -2, 69, 101, 0, 0, 98, 0, 67,
7, 0, 32, 0, 0, 49, 79, -2, 50, 26,
32, 13, -2, 0, 100, 103, 96, 64, 26, 74,
23, 58, 60, 0, 80, 81, 83, 0, 86, 0,
32, 19, 10, 28, 0, -2, 0, 0, 26, 0,
77, 0, 0, 78, 89, 88, 91, 0, 66, 8,
15, 24, 0, 82, 0, 0, 17, 13, 32, 84,
90, 31, 26, 32, 23, 25
};
typedef struct {
char *t_name;
int t_val;
} yytoktype;
/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */
/*
** Skeleton parser driver for yacc output
*/
/*
** yacc user known macros and defines
*/
#define YYERROR goto yyerrlab
#define YYACCEPT { free(yys); free(yyv); return(0); }
#define YYABORT { free(yys); free(yyv); return(1); }
#define YYBACKUP( newtoken, newvalue )
126
{
if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )
{
yyerror( "syntax error - cannot backup" );
goto yyerrlab;
}
yychar = newtoken;
yystate = *yyps;
yylval = newvalue;
goto yynewstate;
}
#define YYRECOVERING() (!!yyerrflag)
#ifndef YYDEBUG
# define YYDEBUG 1 /* make debugging
available */
#endif
/*
** user known globals
*/
int yydebug; /* set to 1 to get
debugging */
/*
** driver internal defines
*/
#define YYFLAG (-1000)
/*
** static variables used by the parser
*/
static YYSTYPE *yyv; /* value stack */
static int *yys; /* state stack */
static YYSTYPE *yypv; /* top of value stack */
static int *yyps; /* top of state stack */
static int yystate; /* current state */
static int yytmp; /* extra var (lasts
between blocks) */
int yynerrs; /* number of errors */
int yyerrflag; /* error recovery flag */
int yychar; /* current input
token number */
/*
** yyparse - return 0 if worked, 1 if syntax error not recovered from
*/
int yyparse()
{
// register YYSTYPE *yypvt; /* top of value stack for $vars
*/
YYSTYPE *yypvt; /* top of value stack for $vars */
unsigned yymaxdepth = YYMAXDEPTH;
/*
** Initialize externals - yyparse may be called more than once
*/
127
yyv = (YYSTYPE *) malloc(yymaxdepth * sizeof(YYSTYPE));
yys = (int *) malloc(yymaxdepth * sizeof(int));
if (!yyv || !yys) {
yyerror("out of memory");
return (1);
}
yypv = &yyv[-1];
yyps = &yys[-1];
yystate = 0;
yytmp = 0;
yynerrs = 0;
yyerrflag = 0;
yychar = -1;
goto yystack;
{
// register YYSTYPE *yy_pv; /* top of value stack */
YYSTYPE *yy_pv; /* top of value stack */
// register int *yy_ps; /* top of state stack */
int *yy_ps; /* top of state stack */
// register int yy_state; /* current state */
int yy_state; /* current state */
// register int yy_n; /* internal state number
info */
int yy_n; /* internal state number info */
/*
** get globals into registers.
** branch to here only if YYBACKUP was called.
*/
yynewstate:
yy_pv = yypv;
yy_ps = yyps;
yy_state = yystate;
goto yy_newstate;
/*
** get globals into registers.
** either we just started, or we just finished a
reduction
*/
yystack:
yy_pv = yypv;
yy_ps = yyps;
yy_state = yystate;
/*
** top of for (;;) loop while no reductions done
*/
yy_stack:
/*
** put a state and value onto the stacks
*/
if (++yy_ps >= &yys[yymaxdepth]) { /* room on stack?
*/
/*
** reallocate and recover. Note that pointers
** have to be reset, or bad things will happen
*/
int yyps_index = (yy_ps - yys);
128
int yypv_index = (yy_pv - yyv);
int yypvt_index = (yypvt - yyv);
yymaxdepth += YYMAXDEPTH;
yyv = (YYSTYPE *) realloc((char *) yyv,
yymaxdepth * sizeof(YYSTYPE));
yys = (int *) realloc((char *) yys, yymaxdepth
* sizeof(int));
if (!yyv || !yys) {
yyerror("yacc stack overflow");
return (1);
}
yy_ps = yys + yyps_index;
yy_pv = yyv + yypv_index;
yypvt = yyv + yypvt_index;
}
*yy_ps = yy_state;
*++yy_pv = yyval;
/*
** we have a new state - find out what to do
*/
yy_newstate:
if ((yy_n = yypact[yy_state]) <= YYFLAG)
goto yydefault; /* simple state */
if ((yychar < 0) && ((yychar = yylex()) < 0))
yychar = 0; /* reached EOF */
if (((yy_n += yychar) < 0) || (yy_n >= YYLAST))
goto yydefault;
if (yychk[yy_n = yyact[yy_n]] == yychar) { /*valid
shift */
yychar = -1;
yyval = yylval;
yy_state = yy_n;
if (yyerrflag > 0)
yyerrflag--;
goto yy_stack;
}
yydefault:
if ((yy_n = yydef[yy_state]) == -2) {
if ((yychar < 0) && ((yychar = yylex()) < 0))
yychar = 0; /* reached EOF */
/*
** look through exception table
*/
{
int *yyxi = yyexca;
//register int *yyxi = yyexca;
while ((*yyxi != -1) || (yyxi[1] !=
yy_state)) {
yyxi += 2;
}
while ((*(yyxi += 2) >= 0) && (*yyxi !=
yychar));
if ((yy_n = yyxi[1]) < 0)
YYACCEPT;
}
129
}
/*
** check for syntax error
*/
if (yy_n == 0) { /* have an error */
/* no worry about speed here! */
switch (yyerrflag) {
case 0: /* new error */
yyerror("syntax error");
goto skip_init;
yyerrlab:
/*
** get globals into registers.
** we have a user generated syntax type
error
*/
yy_pv = yypv;
yy_ps = yyps;
yy_state = yystate;
yynerrs++;
skip_init:
case 1:
case 2: /* incompletely recovered
error */
/* try again... */
yyerrflag = 3;
/*
** find state where "error" is a legal
** shift action
*/
while (yy_ps >= yys) {
yy_n = yypact[*yy_ps] +
YYERRCODE;
if (yy_n >= 0 && yy_n < YYLAST
&& yychk[yyact[yy_n]] == YYERRCODE) {
/*
** simulate shift of
"error"
*/
yy_state = yyact[yy_n];
goto yy_stack;
}
/*
** current state has no shift
on
** "error", pop stack
*/
yy_ps--;
yy_pv--;
}
/*
** there is no state on stack with
"error" as
** a valid shift. give up.
*/
YYABORT;
case 3: /* no shift yet; eat a
token */
130
if (yychar == 0) /* reached EOF.
quit */
YYABORT;
yychar = -1;
goto yy_newstate;
}
}
/* end if ( yy_n == 0 ) */
/*
** reduction by production yy_n
** put stack tops, etc. so things right after switch
*/
yytmp = yy_n; /* value to switch over
*/
yypvt = yy_pv; /* $vars top of value
stack */
/*
** Look in goto table for next state
** Sorry about using yy_state here as temporary
** register variable, but why not, if it works...
** If yyr2[ yy_n ] doesn't have the low order bit
** set, then there is no action to be done for
** this reduction. So, no saving & unsaving of
** registers done. The only difference between the
** code just after the if and the body of the if is
** the goto yy_stack in the body. This way the test
** can be made before the choice of what to do is
needed.
*/
{
/* length of production doubled with extra bit
*/
// register int yy_len = yyr2[yy_n];
int yy_len = yyr2[yy_n];
if (!(yy_len & 01)) {
yy_len >>= 1;
yyval = (yy_pv -= yy_len)[1]; /* $$ =
$1 */
yy_state = yypgo[yy_n = yyr1[yy_n]] +
*(yy_ps -= yy_len) + 1;
if (yy_state >= YYLAST || yychk[yy_state
= yyact[yy_state]] != -yy_n) {
yy_state = yyact[yypgo[yy_n]];
}
goto yy_stack;
}
yy_len >>= 1;
yyval = (yy_pv -= yy_len)[1]; /* $$ = $1 */
yy_state = yypgo[yy_n = yyr1[yy_n]] + *(yy_ps -
= yy_len) + 1;
if (yy_state >= YYLAST || yychk[yy_state =
yyact[yy_state]] != -yy_n) {
yy_state = yyact[yypgo[yy_n]];
}
}
/* save until reenter driver code */
yystate = yy_state;
yyps = yy_ps;
yypv = yy_pv;
131
}
/*
** code supplied by user is placed in this switch
*/
switch (yytmp) {
case 2:
{
pc = basepc = maincode;
nlocalvar = 0;
}
break;
case 3:
{
maincode = pc;
}
break;
case 6:
{
pc = basepc = code;
nlocalvar = 0;
}
break;
case 7:
{
if (dfn_debug) {
align(Word);
code_byte(SETFUNCTION);
code_word(yypvt[-5].vWord);
code_word(yypvt[-4].vWord);
}
dfn_codeadjust(0);
}
break;
case 8:
{
if (dfn_debug)
code_byte(RESET);
code_byte(RETCODE);
code_byte(nlocalvar);
s_tag(yypvt[-7].vWord) = T_FUNCTION;
s_bvalue(yypvt[-7].vWord) = calloc(pc - code,
sizeof(Byte));
memcpy(s_bvalue(yypvt[-7].vWord), code, (pc -
code) * sizeof(Byte));
}
break;
case 11:
{
ntemp = 0;
if (dfn_debug) {
align(Word);
code_byte(SETLINE);
code_word(dfn_linenumber);
}
}
break;
case 15:
{
{
132
Byte *elseinit = yypvt[-2].pByte +
sizeof(Word) + 1;
if (pc - elseinit == 0) { /* no
else */
pc -= sizeof(Word) + 1;
/* if (*(pc-1) == NOP) --pc; */
elseinit = pc;
} else {
*(yypvt[-2].pByte) = JMP;
*((Word *) (yypvt[-2].pByte +
1)) = pc - elseinit;
}
*(yypvt[-4].pByte) = IFFJMP;
*((Word *) (yypvt[-4].pByte + 1)) =
elseinit - (yypvt[-4].pByte +
sizeof(Word) + 1);
}
}
break;
case 16:
{
yyval.pByte = pc;
}
break;
case 17:
{
*(yypvt[-3].pByte) = IFFJMP;
*((Word *) (yypvt[-3].pByte + 1)) = pc -
(yypvt[-3].pByte + sizeof(Word) + 1);
*(yypvt[-1].pByte) = UPJMP;
*((Word *) (yypvt[-1].pByte + 1)) = pc -
yypvt[-6].pByte;
}
break;
case 18:
{
yyval.pByte = pc;
}
break;
case 19:
{
*(yypvt[-0].pByte) = IFFUPJMP;
*((Word *) (yypvt[-0].pByte + 1)) = pc -
yypvt[-4].pByte;
}
break;
case 20:
{
{
int i;
if (yypvt[-0].vInt == 0 || nvarbuffer !=
ntemp - yypvt[-2].vInt * 2)
dfn_codeadjust(yypvt[-2].vInt *
2 + nvarbuffer);
for (i = nvarbuffer - 1; i >= 0; i--)
dfn_codestore(i);
if (yypvt[-2].vInt > 1 || (yypvt[-
2].vInt == 1 && varbuffer[0] != 0))
dfn_codeadjust(0);
}
133
}
break;
case 21:
{
dfn_codeadjust(0);
}
break;
case 25:
{
{
Byte *elseinit = yypvt[-1].pByte +
sizeof(Word) + 1;
if (pc - elseinit == 0) { /* no
else */
pc -= sizeof(Word) + 1;
/* if (*(pc-1) == NOP) --pc; */
elseinit = pc;
} else {
*(yypvt[-1].pByte) = JMP;
*((Word *) (yypvt[-1].pByte +
1)) = pc - elseinit;
}
*(yypvt[-3].pByte) = IFFJMP;
*((Word *) (yypvt[-3].pByte + 1)) =
elseinit - (yypvt[-3].pByte +
sizeof(Word) + 1);
}
}
break;
case 26:
{
yyval.vInt = nlocalvar;
}
break;
case 27:
{
ntemp = 0;
}
break;
case 28:
{
if (nlocalvar != yypvt[-3].vInt) {
nlocalvar = yypvt[-3].vInt;
dfn_codeadjust(0);
}
}
break;
case 30:
{
if (dfn_debug) {
align(Word);
code_byte(SETLINE);
code_word(dfn_linenumber);
}
}
break;
case 31:
{
if (dfn_debug)
code_byte(RESET);
code_byte(RETCODE);
134
code_byte(nlocalvar);
}
break;
case 32:
{
align(Word);
yyval.pByte = pc;
code_byte(0); /* open space */
code_word(0);
}
break;
case 33:
{
if (yypvt[-0].vInt == 0) {
dfn_codeadjust(ntemp + 1);
incr_ntemp();
}
}
break;
case 34:
{
yyval.vInt = yypvt[-1].vInt;
}
break;
case 35:
{
code_byte(EQOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 36:
{
code_byte(LTOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 37:
{
code_byte(LEOP);
code_byte(NOTOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 38:
{
code_byte(EQOP);
code_byte(NOTOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 39:
{
code_byte(LEOP);
yyval.vInt = 1;
ntemp--;
}
break;
135
case 40:
{
code_byte(LTOP);
code_byte(NOTOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 41:
{
code_byte(ADDOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 42:
{
code_byte(SUBOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 43:
{
code_byte(MULTOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 44:
{
code_byte(DIVOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 45:
{
code_byte(CONCOP);
yyval.vInt = 1;
ntemp--;
}
break;
case 46:
{
yyval.vInt = 1;
}
break;
case 47:
{
code_byte(MINUSOP);
yyval.vInt = 1;
}
break;
case 48:
{
code_byte(PUSHBYTE);
yyval.pByte = pc;
code_byte(0);
incr_ntemp();
code_byte(CREATEARRAY);
136
}
break;
case 49:
{
*(yypvt[-2].pByte) = yypvt[-0].vInt;
if (yypvt[-1].vLong < 0) { /* there is no
function to be called */
yyval.vInt = 1;
} else {
dfn_pushvar(yypvt[-1].vLong + 1);
code_byte(PUSHMARK);
incr_ntemp();
code_byte(PUSHOBJECT);
incr_ntemp();
code_byte(CALLFUNC);
ntemp -= 4;
yyval.vInt = 0;
if (dfn_debug) {
align(Word);
code_byte(SETLINE);
code_word(dfn_linenumber);
}
}
}
break;
case 50:
{
code_byte(CREATEARRAY);
yyval.vInt = 1;
}
break;
case 51:
{
dfn_pushvar(yypvt[-0].vLong);
yyval.vInt = 1;
}
break;
case 52:
{
code_number(yypvt[-0].vFloat);
yyval.vInt = 1;
}
break;
case 53:
{
align(Word);
code_byte(PUSHSTRING);
code_word(yypvt[-0].vWord);
yyval.vInt = 1;
incr_ntemp();
}
break;
case 54:
{
code_byte(PUSHNIL);
yyval.vInt = 1;
incr_ntemp();
}
break;
case 55:
{
137
yyval.vInt = 0;
if (dfn_debug) {
align(Word);
code_byte(SETLINE);
code_word(dfn_linenumber);
}
}
break;
case 56:
{
code_byte(NOTOP);
yyval.vInt = 1;
}
break;
case 57:
{
code_byte(POP);
ntemp--;
}
break;
case 58:
{
*(yypvt[-2].pByte) = ONFJMP;
*((Word *) (yypvt[-2].pByte + 1)) = pc -
(yypvt[-2].pByte + sizeof(Word) + 1);
yyval.vInt = 1;
}
break;
case 59:
{
code_byte(POP);
ntemp--;
}
break;
case 60:
{
*(yypvt[-2].pByte) = ONTJMP;
*((Word *) (yypvt[-2].pByte + 1)) = pc -
(yypvt[-2].pByte + sizeof(Word) + 1);
yyval.vInt = 1;
}
break;
case 61:
{
code_byte(PUSHNIL);
incr_ntemp();
}
break;
case 63:
{
code_byte(PUSHMARK);
yyval.vInt = ntemp;
incr_ntemp();
}
break;
case 64:
{
code_byte(CALLFUNC);
ntemp = yypvt[-3].vInt - 1;
}
break;
138
case 65:
{
dfn_pushvar(yypvt[-0].vLong);
}
break;
case 66:
{
yyval.vInt = 1;
}
break;
case 67:
{
yyval.vInt = yypvt[-0].vInt;
}
break;
case 68:
{
yyval.vInt = yypvt[-0].vInt;
}
break;
case 69:
{
if (!yypvt[-1].vInt) {
dfn_codeadjust(ntemp + 1);
incr_ntemp();
}
}
break;
case 70:
{
yyval.vInt = yypvt[-0].vInt;
}
break;
case 73:
{
localvar[nlocalvar] = yypvt[-0].vWord;
incr_nlocalvar();
}
break;
case 74:
{
localvar[nlocalvar] = yypvt[-0].vWord;
incr_nlocalvar();
}
break;
case 75:
{
yyval.vLong = -1;
}
break;
case 76:
{
yyval.vLong = yypvt[-0].vWord;
}
break;
case 77:
{
yyval.vInt = yypvt[-1].vInt;
}
break;
case 78:
139
{
yyval.vInt = yypvt[-1].vInt;
}
break;
case 79:
{
yyval.vInt = 0;
}
break;
case 80:
{
yyval.vInt = yypvt[-0].vInt;
}
break;
case 81:
{
yyval.vInt = 1;
}
break;
case 82:
{
yyval.vInt = yypvt[-2].vInt + 1;
}
break;
case 83:
{
align(Word);
code_byte(PUSHSTRING);
code_word(dfn_findconstant(s_name(yypvt[-
0].vWord)));
incr_ntemp();
}
break;
case 84:
{
code_byte(STOREFIELD);
ntemp -= 2;
}
break;
case 85:
{
yyval.vInt = 0;
}
break;
case 86:
{
yyval.vInt = yypvt[-0].vInt;
}
break;
case 87:
{
code_number(1);
}
break;
case 88:
{
yyval.vInt = 1;
}
break;
case 89:
{
140
code_number(yypvt[-1].vInt + 1);
}
break;
case 90:
{
yyval.vInt = yypvt[-3].vInt + 1;
}
break;
case 91:
{
code_byte(STOREFIELD);
ntemp -= 2;
}
break;
case 92:
{
nvarbuffer = 0;
varbuffer[nvarbuffer] = yypvt[-0].vLong;
incr_nvarbuffer();
yyval.vInt = (yypvt[-0].vLong == 0) ? 1 : 0;
}
break;
case 93:
{
varbuffer[nvarbuffer] = yypvt[-0].vLong;
incr_nvarbuffer();
yyval.vInt = (yypvt[-0].vLong == 0) ? yypvt[-
2].vInt + 1 : yypvt[-2].vInt;
}
break;
case 94:
{
int local = dfn_localname(yypvt[-0].vWord);
if (local == -1) /* global var */
yyval.vLong = yypvt[-0].vWord + 1; /*
return positive value */
else
yyval.vLong = -(local + 1); /* return
negative value */
}
break;
case 95:
{
dfn_pushvar(yypvt[-0].vLong);
}
break;
case 96:
{
yyval.vLong = 0; /* indexed variable */
}
break;
case 97:
{
dfn_pushvar(yypvt[-0].vLong);
}
break;
case 98:
{
align(Word);
code_byte(PUSHSTRING);
141
code_word(dfn_findconstant(s_name(yypvt[-
0].vWord)));
incr_ntemp();
yyval.vLong = 0; /* indexed variable */
}
break;
case 99:
{
localvar[nlocalvar] = yypvt[-1].vWord;
incr_nlocalvar();
}
break;
case 100:
{
localvar[nlocalvar] = yypvt[-1].vWord;
incr_nlocalvar();
}
break;
case 101:
{
code_byte(PUSHNIL);
}
break;
case 102:
{
ntemp = 0;
}
break;
case 104:
{
dfn_debug = yypvt[-0].vInt;
}
break;
}
goto yystack; /* reset registers in
driver code */
}
/*
* y_tab.h
*/
typedef union {
int vInt;
long vLong;
float vFloat;
Word vWord;
Byte *pByte;
} YYSTYPE;
extern YYSTYPE yylval;
#define NIL 257
#define IF 258
#define THEN 259
#define ELSE 260
142
#define ELSEIF 261
#define WHILE 262
#define DO 263
#define REPEAT 264
#define UNTIL 265
#define END 266
#define RETURN 267
#define LOCAL 268
#define NUMBER 269
#define FUNCTION 270
#define NAME 271
#define STRING 272
#define DEBUG 273
#define NOT 274
#define AND 275
#define OR 276
#define NE 277
#define LE 278
#define GE 279
#define CONC 280
#define UNARY 281
#define ENDWHILE 300
#define ENDIF 301
143
APÊNDICE B – ARQUIVOS DE CONFIGURAÇÃO DO ASTERISK E
MÓDULO DE CARGA
;;
;; Arquivo de configuração dos módulos do Asterisk
;;
[modules]
; autoload habilitado, instrui o Asterisk a carregar todos os arquivos *.so que encontrar
em /var/lib/asterisk/modules
autoload=yes
; Cada módulo precisa ser carregado antes do núcleo do Asterisk ser inicializado.
;
; A linha abaixo só deverá ser descomentada se o autoload for igual a "no".
;load => pbx_dfn.so
; Como o autoload está habilitado, caso não se pretenda carregar o módulo da
linguagem dfn,
; deve-se remover o comentário da linha abaixo
;noload => pbx_dfn.so
Arquivo sip.conf:
; SIP Configuration - Asterisk
; Exemplo de configuração que será usada na demonstração do trabalho
; Este arquivo contém a autenticação dos ramais.
;
[general]
context=default ; Default context for incoming calls
allowoverlap=no ; Disable overlap dialing support. (Default is yes)
udpbindaddr=0.0.0.0 ; IP address to bind UDP listen socket to (0.0.0.0 binds to
all)
tcpenable=no ; Enable server for incoming TCP connections (default is no)
tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0 binds to all
interfaces)
srvlookup=yes ; Enable DNS SRV lookups on outbound calls
register => username:secret@host/callbackextension
register => 1234:password@mysipprovider.com
; Ramais para teste
[4001]
144
context=from-internal
type=friend
regexten=4001 ; When they register, create extension 1234
defaultuser=4001
secret=4001
callerid="CP" <4001>
host=dynamic
nat=no ; X-Lite is behind a NAT router
canreinvite=no ; Typically set to NO if behind NAT
disallow=all
allow=g729
allow=ulaw
allow=alaw
allow=gsm ; GSM consumes far less bandwidth than ulaw
;allow=all
permit=0.0.0.0/0.0.0.0
[4002]
context=from-internal
type=friend
regexten=4002 ; When they register, create extension 1234
defaultuser=4002
secret=4002
callerid="CP" <4002>
host=dynamic
nat=no ; X-Lite is behind a NAT router
canreinvite=no ; Typically set to NO if behind NAT
disallow=all
allow=g729
allow=ulaw
allow=alaw
allow=gsm ; GSM consumes far less bandwidth than ulaw
;allow=all
permit=0.0.0.0/0.0.0.0
/*
Modulo de carga para o Asterisk
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/pbx.h"
#include "asterisk/paths.h" /* ast_config_AST_CONFIG_DIR */
#include "dfn/dfn.h"
#include "dfn/dfnlib.h"
static char *config = "extensions.dfn";
145
//static char *registrar = "pbx_dfn";
static int pbx_load_module(void);
static int exists(struct ast_channel *chan, const char *context, const
char *exten, int priority, const char *callerid, const char *data);
static int canmatch(struct ast_channel *chan, const char *context,
const char *exten, int priority, const char *callerid, const char
*data);
static int matchmore(struct ast_channel *chan, const char *context,
const char *exten, int priority, const char *callerid, const char
*data);
static int exec(struct ast_channel *chan, const char *context, const
char *exten, int priority, const char *callerid, const char *data);
static struct ast_switch dfn_switch = {
.name = "DFN",
.description = "DFN Language PBX Switch",
.exists = exists,
.canmatch = canmatch,
.exec = exec,
.matchmore = matchmore,
};
static int pbx_load_module(void)
{
char *rfilename;
if (config[0] == '/')
rfilename = (char *)config;
else {
rfilename = alloca(strlen(config) +
strlen(ast_config_AST_CONFIG_DIR) + 2);
sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR,
config);
}
if (access(rfilename,R_OK) != 0) {
ast_log(LOG_NOTICE, "File %s not found; DFN Extension
Language module declining loadn", rfilename);
return AST_MODULE_LOAD_DECLINE;
}
dfn_execfile(rfilename);
ast_log(LOG_NOTICE, "DFN Extension Language Loadedn");
return AST_MODULE_LOAD_SUCCESS;
}
static int load_module(void)
{
ast_log(LOG_NOTICE, "Starting DFN Extension Language load
process.n");
return (pbx_load_module());
}
static int unload_module(void)
146
{
ast_log(LOG_NOTICE, "DFN Extension Language Unloadedn");
return 0;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DFN Extension Language");
147
APÊNDICE C – ARQUIVO DE CONFIGURAÇÃO DO XEN
#
# Arquivo de configuração da máquina virtual a ser usada no trabalho
#
kernel = "/images/TCC/boot/vmlinuz-xen"
ramdisk = "/images/TCC/boot/initrd-xen"
builder='linux'
memory = 512
name = "TCC_VM_DFN"
#uuid = "06ed00fe-1162-4fc4-b5d8-11993ee4a8b9"
# Number of Virtual CPUS to use, default is 1
vcpus = 1
vif = [ 'mac=00:16:3e:00:00:11, bridge=br0' ]
disk = [ 'file:/images/TCC/vdisks/sda_vdisk_12GB.img,xvda,w',
'file:/images/TCC/vdisks/sdb_vdisk_16GB.img,xvdb,w' ]
root = "/dev/xvda2"
vfb = [ 'vnc=1,vnclisten=0.0.0.0,vncunused=1,vncpasswd=reurbanisatus' ]
# Set root device.
#root = "/dev/hda1"
# Extra arguments to pass to the kernel.
extra = "xencons=xvc console=xvc0 video=tty"
#on_poweroff = 'destroy'

Mais conteúdo relacionado

PPTX
.NET Open Source 2009
DOCX
Compilador
PDF
Introdução à Computação Aula 09 - Algoritmos (Linguagens de Programação)
PDF
[AIIM16] How Regulatory Data Can Set the Narrative for an Analytics Opportunity
PPS
Democraciacomoformadegobierno 100521225402-phpapp02
PDF
Gestión del seguimiento en teleformación.
PDF
Mule ESB Introduccion
PDF
"Крокодил" №16 1924 год
.NET Open Source 2009
Compilador
Introdução à Computação Aula 09 - Algoritmos (Linguagens de Programação)
[AIIM16] How Regulatory Data Can Set the Narrative for an Analytics Opportunity
Democraciacomoformadegobierno 100521225402-phpapp02
Gestión del seguimiento en teleformación.
Mule ESB Introduccion
"Крокодил" №16 1924 год

Destaque (19)

PPTX
Presentación mailing
PPTX
Documental
PPTX
Emotional Webdesign - How to make the user smile - Frontend Conf Zürich 2011
PPT
Pixel Web
PDF
La Estrategia de Contenidos
PPT
T 504 1 – 2 – 3 - 8
DOCX
Cgt informa permisos del convenio de limpieza catalunya
PDF
Product Catalog - Prime-Dent - Chicago - USA -
PDF
What Is Wimax ? A Tutorial from Quantum Networks, LLC
PDF
The truth about mobile business intelligence 5 common myths debunked
PDF
Internship Report - Rao Saim Zafar
PDF
UGM 2014 SmartTools for Non-clinical Users
PPTX
POWER LOS MITOS
PPTX
From Community to Commerce: Making the ROI Connection
PPTX
On life, universe and the 4 4-2
PDF
Mercedes fashion week
PDF
Triggers o disparadores en MySQL
DOCX
Teoria da Administração
Presentación mailing
Documental
Emotional Webdesign - How to make the user smile - Frontend Conf Zürich 2011
Pixel Web
La Estrategia de Contenidos
T 504 1 – 2 – 3 - 8
Cgt informa permisos del convenio de limpieza catalunya
Product Catalog - Prime-Dent - Chicago - USA -
What Is Wimax ? A Tutorial from Quantum Networks, LLC
The truth about mobile business intelligence 5 common myths debunked
Internship Report - Rao Saim Zafar
UGM 2014 SmartTools for Non-clinical Users
POWER LOS MITOS
From Community to Commerce: Making the ROI Connection
On life, universe and the 4 4-2
Mercedes fashion week
Triggers o disparadores en MySQL
Teoria da Administração
Anúncio

Semelhante a cco-12 (20)

PPTX
Isc aula 7
PDF
Framework Entities - Dissertação
PPTX
Delphi Prism 2011
PPTX
Projetos Mono e Moonlight
DOCX
Visual basic
PPT
Linguagem de programação
PDF
Vagrant uma ferramenta realmente útil e versátil
PDF
2-Compreender os principais conceitos de desenvolvimento.pdf
PPT
Programação concorrente
PPTX
Containers com docker #CPRecife4
PDF
Apostila sobre o Visualg
PDF
Mercurianos - .Net na Prática - Da instalação até o debug da nossa API em um ...
PDF
PDF
Turbinando microsserviços em PHP
PPTX
Entrega contínua com arquitetura distribuida
PPT
Produtividade net
PDF
Linguagens de programação 03-12-09
PDF
Linguagens de programação 03-12-09
PDF
Interoperabilidade com .NET em ambiente Mainframe
Isc aula 7
Framework Entities - Dissertação
Delphi Prism 2011
Projetos Mono e Moonlight
Visual basic
Linguagem de programação
Vagrant uma ferramenta realmente útil e versátil
2-Compreender os principais conceitos de desenvolvimento.pdf
Programação concorrente
Containers com docker #CPRecife4
Apostila sobre o Visualg
Mercurianos - .Net na Prática - Da instalação até o debug da nossa API em um ...
Turbinando microsserviços em PHP
Entrega contínua com arquitetura distribuida
Produtividade net
Linguagens de programação 03-12-09
Linguagens de programação 03-12-09
Interoperabilidade com .NET em ambiente Mainframe
Anúncio

cco-12

  • 1. UNIVERSIDADE ANHEMBI MORUMBI DÊNIO ROBSON VAL SILVA FELIPE BARATOJO FLORES NEIDE SOARES SALES LINGUAGEM DE PROGRAMAÇÃO INTERPRETADA UTILIZADA NA CONFIGURAÇÃO DE APLICATIVOS VOLTADOS PARA SISTEMAS MULTI-PLATAFORMA COM IMPLEMENTAÇÃO EM AMBIENTE PARAVIRTUALIZADO São Paulo 2010
  • 2. DÊNIO ROBSON VAL SILVA FELIPE BARATOJO FLORES NEIDE SOARES SALES LINGUAGEM DE PROGRAMAÇÃO INTERPRETADA UTILIZADA NA CONFIGURAÇÃO DE APLICATIVOS VOLTADOS PARA SISTEMAS MULTI-PLATAFORMA COM IMPLEMENTAÇÃO EM AMBIENTE PARAVIRTUALIZADO Orientador: Professor Msc. Luciano Freire São Paulo 2010 Monografia apresentada como exigência parcial para a obtenção do título de bacharel em Ciência da Computação pela Universidade Anhembi Morumbi
  • 3. UNIVERSIDADE ANHEMBI MORUMBI BACHARELADO EM CIÊNCIA DA COMPUTAÇÃO DÊNIO ROBSON VAL SILVA FELIPE BARATOJO FLORES NEIDE SOARES SALES LINGUAGEM DE PROGRAMAÇÃO INTERPRETADA UTILIZADA NA CONFIGURAÇÃO DE APLICATIVOS VOLTADOS PARA SISTEMAS MULTI-PLATAFORMA COM IMPLEMENTAÇÃO EM AMBIENTE PARAVIRTUALIZADO Aprovado ______________________________________________________________________ Prof. Msc. Luciano Freire Universidade Anhembi Morumbi ______________________________________________________________________ Prof................................ Universidade Anhembi Morumbi ______________________________________________________________________ Prof. .............................. Universidade Anhembi Morumbi Monografia apresentada como exigência parcial para a obtenção do título de bacharel em Ciência da Computação pela Universidade Anhembi Morumbi
  • 4. UNIVERSIDADE ANHEMBI MORUMBI Dedicamos este trabalho de conclusão de curso a todos os nossos familiares que nos apoiaram, à Anhembi Morumbi por ter acreditado no Curso Superior em Ciência da Computação e ao orientador, Professor que, com dedicação e conhecimento, orientou-nos no decorrer deste trabalho.
  • 5. AGRADECIMENTOS Agradecemos aos colegas que contribuíram e incentivaram para a realização deste trabalho e também aos professores que com sabedoria nos acompanharam nestes anos em que decorreu o curso e, em especial, ao nosso orientador que nos acompanhou em todas as etapas deste trabalho. Também aos amigos e à família pela compreensão de nossa ausência para a elaboração do mesmo.
  • 6. “Nossas dúvidas são traidoras e nos fazem perder o que, com freqüência, poderíamos ganhar, por simples medo de arriscar.” (William Shakespeare)
  • 7. RESUMO Esta monografia apresenta um breve estudo sobre a tecnologia da virtualização explorando os benefícios dos tipos de virtualização existentes, e principalmente da paravirtualização, com o objetivo de desenvolver uma linguagem interpretada para ser utilizada em aplicativos hospedeiros. São praticamente inexistentes as linguagens de programação voltadas à configuração e, embora a linguagem seja voltada a qualquer plataforma, a implementação foi realizada em um ambiente paravirtualizado por facilitar a criação de ambientes diversificados sem necessidade de hardware adicional, apresentando um desempenho razoável. Este trabalho não envolve a criação de um compilador, mas de uma linguagem, na condição de linguagem de extensão aplicada ao software hospedeiro Asterisk e às etapas para a implementação da mesma em um ambiente paravirtualizado. Para o desenvolvimento deste trabalho, foi necessária a realização de um estudo a respeito dos tipos de virtualização, através da análise de documentos da IBM, Xen, VmWare e outros fabricantes importantes, para que então optássemos pela utilização do Xen como software de virtualização. Quatro etapas principais foram necessárias para a conclusão do trabalho: a pesquisa a respeito das tecnologias existentes, tanto para virtualização como para utilização da linguagem interpretada; a criação do ambiente paravirtualizado; a criação da linguagem interpretada utilizada no aplicativo hospedeiro Asterisk e a junção do ambiente virtualizado criado com a linguagem desenvolvida. Palavras-Chave: Virtualização, Linguagem Interpretada, Xen, Asterisk.
  • 8. ABSTRACT This monograph presents a brief study about virtualization technology by exploring the benefits of existing virtualization types, and mainly the paravirtualization with the goal of developing an interpreted language to be used in host applications. Practically it doesn’t exist programming languages directed to configuration and although the language is geared to any platform, the implementation was done in a paravirtualized environment by facilitating the creation of diversified environments without requiring additional hardware and showing reasonable performance. The work does not involve the creation of a compiler, but a language, as an extension language applied to the host software Asterisk, and the steps to implement it in a paravirtualized environment. To develop the work was necessary to carry out a study about the types of virtualization through documents from IBM, Xen, VmWare and other major manufacturers to take back the conclusion that we should use the Xen virtualization software. Four main steps were necessary for completion of the work: research on existing technologies, for both to use virtualization as the interpreted language; the creation of paravirtualized environment; the creation of the interpreted language used in the host application Asterisk, and the join of the virtualized environment created with the language developed. Key words: Virtualization, Interpreted Language, Xen, Asterisk.
  • 9. LISTA DE FIGURAS Figura 1 - Várias máquinas virtuais em um único hardware.......................................... 17 Figura 2 – Tecnologia com mais impacto na transformação dos processos de negócio 20 Figura 3 - Emulação de hardware................................................................................... 21 Figura 4 - Virtualização completa .................................................................................. 22 Figura 5 - Paravirtualização............................................................................................ 23 Figura 6 - Virtualização de sistema operacional ............................................................ 24 Figura 7 – VmWare ESX ............................................................................................... 28 Figura 8 – Componentes do Xen.................................................................................... 32 Figura 9 – User mode Linux........................................................................................... 33 Figura 10 - Linguagem interpretada............................................................................... 38 Figura 11 - Linguagem compilada.................................................................................. 40 Figura 12 – Instalação Xen............................................................................................. 44 Figura 13 – Instalando o Hypervisor e Ferramentas 1 ................................................... 45 Figura 14 – Domínio 0 configurado ............................................................................... 45 Figura 15 – Processo de inicialização............................................................................. 47 Figura 16 – Tratamento de chamada .............................................................................. 47 Figura 17 – Compilação do módulo ............................................................................... 48 Figura 18 – Diretório de módulos do Asterisk ............................................................... 48 Figura 19 – Arquivo sip.conf.......................................................................................... 51 Figura 20 – Topologia final............................................................................................ 59 Figura 21 – Módulo carregado com sucesso .................................................................. 60 Figura 22 – Módulo não carrega sem extensions.dfn..................................................... 60 Figura 23 – CDR ............................................................................................................ 61 Figura 24 – Ligação realizada ........................................................................................ 62
  • 10. LISTA DE TABELAS Tabela 1 – Ferramentas de virtualização.........................................................................26 Tabela 2 – Suporte Xen 3.0.............................................................................................30 Tabela 3 – Suporte Xen 2.0.............................................................................................31 Tabela 4 – Tipos de linguagens.......................................................................................35
  • 11. LISTA DE ABREVIATURAS E SIGLAS AMD – Advanced Micro Devices AMD-V – Advanced Micro Devices Virtualization API (Application Programming Interface): Interface de Programação de Aplicações BIOS (Basic Input/Output System): Sistema básico de entrada/saída CD-ROM (Compact Disk Read Only Memory): Disco Compacto com Memória somente leitura CMS – Conversational Monitor System CPU (Central Processing Unit): Unidade de Processamento Central GHz – Gigahertz HD (Hard Disk): Disco Rígido IAX – Inter Asterisk Exchange IBM – International Business Machines IDC – International Data Corporation IDE (Integrated Development Environment): Ambiente de Desenvolvimento Integrado IETF – Internet Engineering Task Force Intel-VT (Intel Virtualization Technology): Tecnologia de Virtualização da Intel KVM – Kernel-based Virtual Machine MGCP – Media Gateway Control Protocol MIT – Massachusetts Institute of Technology PBX – Private Branch Exchanges PSTN – Public Switched Telephone Network RAM (Random Access Memory): Memória de Acesso Aleatório
  • 12. SIP – Session Initiation Protocol SLA (Service Level Agreement): Acordo de Nível de Serviço TCP – Transmission Control Protocol TI – Tecnologia da Informação UDP – User Datagram Protocol UML – User Mode Linux USB – Universal Serial Bus VBS – Visual Basic Script VGA – Video Graphics Array VM (Virtual Machine): Máquina Virtual VMM (Virtual Machine Monitor): Monitor de Máquina Virtual VoIP (Voice over IP): Voz Sobre IP VT (Virtualization Technology): Tecnologia de Virtualização
  • 13. SUMÁRIO 1 INTRODUÇÃO...................................................................................................................... 15 1.1 OBJETIVOS ..................................................................................................................... 15 1.2 JUSTIFICATIVA.............................................................................................................. 15 1.3 ABRANGÊNCIA.............................................................................................................. 16 1.4 ESTRUTURA DO TRABALHO...................................................................................... 16 2 VIRTUALIZAÇÃO ............................................................................................................... 17 2.1 INTRODUÇÃO SOBRE VIRTUALIZAÇÃO................................................................. 17 2.2 HISTÓRIA DA VIRTUALIZAÇÃO................................................................................ 18 2.3 NECESSIDADE DA VIRTUALIZAÇÃO ....................................................................... 19 2.4 EMULAÇÃO DE HARDWARE...................................................................................... 21 2.5 VIRTUALIZAÇÃO COMPLETA.................................................................................... 22 2.6 PARAVIRTUALIZAÇÃO................................................................................................ 23 2.7 VIRTUALIZAÇÃO DE SISTEMA OPERACIONAL..................................................... 24 2.8 HARDWARE COM SUPORTE À VIRTUALIZAÇÃO ................................................. 24 3 FERRAMENTAS PARA VIRTUALIZAÇÃO.................................................................... 26 3.1 BOCHS ............................................................................................................................. 26 3.2 QEMU............................................................................................................................... 27 3.3 VMWARE......................................................................................................................... 27 3.4 LINUX KVM.................................................................................................................... 29 3.5 HYPER-V ......................................................................................................................... 29 3.6 XEN................................................................................................................................... 29 3.7 UML.................................................................................................................................. 33 4 ASTERISK.............................................................................................................................. 35 4.1 SIP..................................................................................................................................... 35 4.2 MGCP ............................................................................................................................... 36 4.3 IAX.................................................................................................................................... 36 5. LINGUAGENS DE PROGRAMAÇÃO.............................................................................. 37 5.1 LINGUAGENS INTERPRETADAS................................................................................ 38 5.1.1 LINGUAGEM DE EXTENSÃO OU SCRIPT.......................................................... 39 5.2 LINGUAGENS COMPILADAS ...................................................................................... 40 6 METODOLOGIA .................................................................................................................. 41 6.1 VIRTUALIZAÇÃO .......................................................................................................... 41 6.2 LINGUAGEM INTERPRETADA ................................................................................... 42 6.3 TESTES FINAIS............................................................................................................... 42 7 DESENVOLVIMENTO ........................................................................................................ 44
  • 14. 7.1 CONFIGURAÇÃO DO AMBIENTE............................................................................... 44 7.2 DETALHES DE IMPLEMENTAÇÃO DA PARAVIRTUALIZAÇÃO ......................... 44 7.3 INSTALAÇÃO ASTERISK ............................................................................................. 46 7.3.1 INTERAÇÃO ENTRE O ASTERISK E O MÓDULO DA LINGUAGEM DFN ..... 47 7.4 DESENVOLVIMENTO DA LINGUAGEM INTERPRETADA PARA SISTEMA MULTI-PLATAFORMA........................................................................................................ 51 7.4.1 VARIÁVEIS E TIPOS............................................................................................... 52 7.4.2 ATRIBUIÇÕES ......................................................................................................... 53 7.4.3 OPERADORES ARITMÉTICOS E RELACIONAIS............................................... 53 7.4.4 ORDEM DE PRECEDÊNCIA DOS OPERADORES............................................... 54 7.4.5 COMENTÁRIOS....................................................................................................... 54 7.4.6 FUNÇÕES DA LINGUAGEM.................................................................................. 54 7.4.6.1 FUNÇÕES DE MANIPULAÇÃO DE STRING.................................................... 54 7.4.7 CONTROLE DE FLUXO E LAÇOS ITERATIVOS................................................ 56 7.4.7.1 TOMADAS DE DECISÃO COM IF.................................................................... 56 7.4.7.2 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO INÍCIO (WHILE) 57 7.4.7.3 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO FIM (REPEAT/UNTIL).............................................................................................................. 57 7.4.8 ANALISADOR DE EXPRESSÃO............................................................................ 58 7.5 IMPLEMENTAÇÃO DA LINGUAGEM INTERPRETADA NO SISTEMA PARAVIRTUALIZADO ........................................................................................................ 59 8 CONCLUSÃO ....................................................................................................................... 63 REFERÊNCIAS BIBLIOGRÁFICAS .................................................................................... 64 APÊNDICE A – CÓDIGO FONTE DA LINGUAGEM ....................................................... 68 APÊNDICE B – ARQUIVOS DE CONFIGURAÇÃO DO ASTERISK E MÓDULO DE CARGA.................................................................................................................................... 143 APÊNDICE C – ARQUIVO DE CONFIGURAÇÃO DO XEN ......................................... 147
  • 15. 15 1 INTRODUÇÃO A virtualização possibilita a definição de diversas máquinas lógicas em apenas um único hardware, fazendo com que a utilização de recursos aumente, além de facilitar a consolidação e segurança de ambientes computacionais. Segundo Bernard Golden e Clark Scheffy (2008, p.06 e 07), muitos data centers possuem máquinas sendo utilizadas com apenas 10% a 15% de sua capacidade total de processamento e, além disso, a necessidade de máquinas distintas para aplicações diferentes aumenta ainda mais a infra-estrutura, dificultando a administração, aumentando os gastos com manutenção, gerenciamento e energia. Uma linguagem de programação interpretada como linguagem de extensão permite a utilização de aplicativos hospedeiros em ambiente multi-plataforma, pois esta não está vinculada à linguagem de máquina do ambiente e sim ao interpretador. A razão para o desenvolvimento deste trabalho baseia-se no fato de que hoje em dia são praticamente inexistentes linguagens de programação voltadas à configuração de aplicativos que exijam agilidade na administração, alta disponibilidade e resiliência. Alguns aplicativos já possuem essa tecnologia, como por exemplo, o software de PBX VoIP Asterisk, que pode fazer uso de linguagens de extensão como alternativa à utilização de arquivos de configuração para facilitar seu uso e administração. 1.1 OBJETIVOS O objetivo deste trabalho é desenvolver uma linguagem de programação interpretada (extensível) para permitir maior flexibilidade na parametrização de aplicativos que necessitem do uso de configuração para o seu funcionamento. Como exemplo, esta linguagem será voltada para o software Asterisk. Será utilizada a paravirtualização como ambiente de implementação do Asterisk e da linguagem desenvolvida facilitando a administração e possibilitando um SLA (Service Level Agreement) elevado. 1.2 JUSTIFICATIVA A justificativa deste trabalho consiste nas dificuldades práticas em criar ambientes configuráveis de forma flexível. São praticamente inexistentes as linguagens de programação voltadas à configuração, principalmente no âmbito dos sistemas embarcados. Esta linguagem, ou mais precisamente, interpretador, é direcionado a qualquer plataforma. Entretanto, neste trabalho a implementação será realizada em um
  • 16. 16 ambiente paravirtualizado, visto que a paravirtualização é uma tecnologia que facilita a criação de ambientes diversificados, sem a necessidade de adquirir hardwares com suporte a virtualização, além de facilitar a implementação de máquinas adicionais com sistemas que podem ou não estar integrados uns com os outros e com confiabilidade. 1.3 ABRANGÊNCIA Este trabalho abrange o desenvolvimento da linguagem na forma de interpretador na condição de linguagem de extensão, que será implementada em um ambiente paravirtualizado. Não faz parte do escopo deste trabalho o desenvolvimento de um compilador, mas sim de uma linguagem que possa ser embutida em outros aplicativos, que neste caso será no software Asterisk. O próprio software Asterisk é quem agirá como interpretador. Embora a virtualização não seja uma condição obrigatória para o uso da linguagem, ela será utilizada na implementação da solução, dada sua flexibilidade. 1.4 ESTRUTURA DO TRABALHO A estrutura do trabalho está dividida nos seguintes capítulos: O capítulo 2 aborda a definição de virtualização e as técnicas existentes. O capítulo 3 aborda a explicação das ferramentas de virtualização mais conhecidas no mercado, tanto as livres quanto as pagas. O capítulo 4 mostra o que é o Asterisk e suas principais características. O capítulo 5 trata do conceito de linguagem interpretada com exemplos de aplicação. O capítulo 6 aborda a metodologia do trabalho. O capítulo 7 mostra a criação do ambiente paravirtualizado em preparação para implementação da linguagem interpretada, assim como os detalhes da criação da linguagem e utilização da API do Asterisk para que este entenda e interprete a linguagem desenvolvida. Além disso, haverá detalhes da implementação da linguagem no ambiente paravirtualizado, com considerações e resultados finais. O capítulo 8 aborda a conclusão do trabalho e trabalhos futuros.
  • 17. 17 2 VIRTUALIZAÇÃO Em meio às muitas tecnologias que surgiram nos últimos anos, a virtualização é um conceito que está sendo cada vez mais utilizado na área de tecnologia da informação. De acordo com a IBM (2005), a virtualização simplifica a infra-estrutura, reduz a complexidade e os custos otimizando os recursos. Para qualquer área dentro de uma empresa, a virtualização pode ser útil, pois muitos sistemas podem estar baseados e implementados em sistemas virtualizados, aumentando a disponibilidade, resiliência e facilitando a administração. Sempre há prós e contras a respeito de qualquer conceito, inclusive a virtualização. Neste capítulo serão apresentados os conceitos, os tipos de virtualização mais conhecidos, os benefícios de se utilizar a tecnologia citada e a diversidade de ferramentas existentes. 2.1 INTRODUÇÃO SOBRE VIRTUALIZAÇÃO De acordo com Bernard Golden e Clark Scheffy (2008, p.06 e 07), hoje muitos data centers possuem máquinas sendo utilizadas com apenas 10% a 15% da capacidade total de processamento. Em outras palavras, 85% a 90% da capacidade das máquinas não são utilizadas. Além disso, a necessidade de novas aplicações e sistemas faz com que novos servidores e máquinas de todos os tipos sejam adquiridos e que os data centers precisem de cada vez mais espaço para disposição de servidores. Figura 1 - Várias máquinas virtuais em um único hardware Fonte: VmWare (2008)
  • 18. 18 De maneira simples, a virtualização é uma técnica para se utilizar diversos sistemas operacionais distintos, mas em um único hardware, conforme ilustra a Figura 1. De acordo com Jones (2006), virtualizar significa pegar algo que está em uma forma e fazê-la parecer de outra forma. Virtualizar um computador significa fazê-lo parecer múltiplos computadores ou um computador completamente diferente. Dependendo do ponto de vista, também pode significar fazer com que muitos computadores pareçam um único computador. Isto pode ser chamado de Server Agregation (agregação de servidores) ou Grid Computing (grid de computadores). A virtualização emula componentes de hardware para o sistema operacional através de técnicas, hardwares e softwares de virtualização. Essas técnicas são hoje utilizadas tanto para desktops quanto para servidores. O conceito de virtualização não é algo recente, mas após uma longa jornada passou a evoluir de maneira considerável nos últimos anos. Surgiram então diversas abordagens, mostrando varias vantagens e desvantagens dependendo da técnica a ser utilizada. [...] Uma máquina virtual não pode ser comprometida pela operação de qualquer outra máquina virtual. Ela fornece um ambiente computacional privado, seguro e confiável para seus usuários. [...] Novas facilidades, como sistemas de banco de dados ou suporte a dispositivos especializados podem ser adicionados sem modificação ou corrompimento das atuais capacidades. [...] (CREASY, 1981, p.487) 2.2 HISTÓRIA DA VIRTUALIZAÇÃO De acordo com a IBM (2006), a virtualização não é um tópico novo, pois o conceito de virtualização surgiu por volta do ano de 1960, quando a IBM, em conjunto com o MIT (Massachusetts Institute of Technology), tratava de um projeto chamado M44/44X. A meta era avaliar os conceitos de sistema de compartilhamento de tempo (Compatible Time-Share System, como era chamado). A máquina principal era um IBM 704 (M44) e cada máquina virtual era uma imagem experimental da máquina principal (44X). O espaço de endereçamento do 44X residia na hierarquia de memória do M44 e, além disso, era utilizado um sistema de memória virtual e multiprogramação.
  • 19. 19 Este Mainframe executava duas máquinas virtuais, uma para executar programas e outra para o sistema. O sistema operacional do Mainframe era chamado de Supervisor. Alguns anos depois a IBM desenvolveu os computadores da família 360. Foi lançado o Mainframe System/360. Nesse Mainframe o hardware era acessado pela interface chamada VMM (Virtual Machine Monitor). O VMM permitia a execução das máquinas virtuais onde cada máquina executava uma instância do sistema operacional principal. O VMM executava diretamente na camada de hardware, permitindo múltiplas máquinas virtuais (VMs). Cada VM podia executar uma instância do sistema operacional – nos dias mais antigos isto era o CMS, ou Conversational Monitor System. A VM continuou a avançar, e hoje podemos encontrá-la sendo executada no mainframe System z9. Isto fornece compatibilidade antiga até mesmo com a linha System/360. (JONES, 2006) De acordo com Manfrin (2010), na época, os Mainframes eram máquinas X86 com um grande poder de processamento, mas que não eram completamente aproveitadas, utilizando somente de 10 a 15% de sua capacidade, pois normalmente eram implementadas para aplicações específicas, diminuindo os riscos de ficarem fora de produção. 2.3 NECESSIDADE DA VIRTUALIZAÇÃO De acordo com a VmWare (2010), a virtualização foi praticamente abandonada durante os anos 80 e 90, quando aplicações cliente-servidor, servidores e desktops X86 começaram a ser distribuídos. A adoção de sistemas operacionais Linux e Windows como sistemas para servidores começaram a ser o padrão da indústria. Com esse crescimento de servidores e desktops X86, passou a surgir uma nova infra-estrutura de TI e novos desafios operacionais. A VmWare, uma das empresas que fornecem tecnologia de virtualização, informa que alguns desses desafios são: - Baixa utilização de infraestrutura. De acordo com a IDC (International Data Corporation), a distribuição de servidores x86 atinge uma média de utilização de 10% a 15% da capacidade total. As organizações geralmente executam uma aplicação por servidor para evitar riscos de vulnerabilidade, ou seja, para que problemas afetando uma aplicação, não afetem a disponibilidade de outra que esteja no mesmo servidor;
  • 20. 20 - Aumento do custo da infraestrutura física. É necessário suprir os custos operacionais do crescimento da infraestrutura. A maioria dos ambientes computacionais precisa estar disponível em quase 100% do tempo, resultando em consumo de energia, resfriamento, e custos que não variam; - Aumento do custo de gerenciamento de TI. Devido aos ambientes computacionais se tornarem mais complexos, os custos associados ao nível de educação especializada e experiência requerida para o gerenciamento da infraestrutura aumentam consideravelmente; - Proteção insuficiente contra desastres e falhas. Organizações são afetadas devido à inacessibilidade a aplicações críticas. Ameaças a segurança por meio de ataques, desastres naturais e terrorismos aumentaram a importância do planejamento continuo dos negócios, tanto para desktops como para servidores; - Alta manutenção de desktops de usuários finais. Diversos desafios são apresentados às empresas quando gerenciam e fornecem segurança para desktops. Controlar e gerenciar um ambiente de desktop distribuído, com diretivas de acesso e segurança sem impactar na habilidade do usuário de trabalhar efetivamente, é complexo e caro. De acordo com uma pesquisa realizada com empresas de IT (Information Technology) e com LOB (Line Of Business – outras áreas de negócio) pela IDC (2008), a tecnologia que tem mais impacto na transformação dos processos de negócio na área de TI, conforme Gráfico 1, é a virtualização. Figura 2 – Tecnologia com mais impacto na transformação dos processos de negócio Fonte: IDC (2008)
  • 21. 21 Devido a essas e outras necessidades, as técnicas de virtualização foram surgindo e evoluindo em grande escala. Segundo a Gartner (2008), é esperado que o número de computadores virtualizados cresça de menos de 5 milhões em 2007 para 660 milhões em 2011, e Pettey (2008) diz que a virtualização é o problema que terá maior impacto até 2012, modificando infraestruturas e operações e modificando também a maneira de comprar e de gerenciar. 2.4 EMULAÇÃO DE HARDWARE De acordo com Jones (2007), a emulação de hardware nada mais é do que a virtualização do hardware. Provavelmente quando se fala em virtualização, a emulação de hardware é indicada como a mais complexa. Através das camadas virtuais de hardware é possível criar diferentes ambientes utilizando a mesma máquina física, conforme ilustra a Figura 2. Com a emulação de hardware alguns benefícios são apresentados, como por exemplo: É possível simular diversos processadores, mesmo que o hardware real possua apenas um processador físico. Pode-se também executar diversas máquinas virtuais, cada uma simulando um processador diferente. Uma das utilizações mais importantes da emulação de hardware é no desenvolvimento de firmware e hardware. Ao invés de esperar até que o hardware esteja disponível, os desenvolvedores de firmware podem utilizar o hardware VM alvo para validar muitos aspectos de seus códigos atuais em simulação. (JONES, 2006) Este tipo de virtualização precisa de um software que entenda as instruções da arquitetura que se deseja emular. Esta é a técnica utilizada pelos desenvolvedores de emuladores de vídeo-game, na qual o software irá converter as instruções recebidas da Figura 3 - Emulação de hardware Fonte: IBM (2006)
  • 22. 22 arquitetura em que se está emulando, para que o sistema operacional convidado (também conhecido por GuestOS) possa entender as instruções. 2.5 VIRTUALIZAÇÃO COMPLETA De acordo com a VmWare (2007) a virtualização completa é uma técnica utilizada para fornecer um ambiente de máquina virtual, que simula de maneira completa o hardware como réplica do hardware real. Segundo Menascé (2005), o sistema operacional executado através de virtualização completa, que pode ser chamado de sistema operacional convidado, não necessita de modificações, visto que é executado através do VMM, o monitor de máquina virtual. O VMM é uma camada de software mais próxima ao hardware. Esta camada, que está entre o hardware e o sistema operacional convidado concede uma abstração da máquina virtual, conforme ilustra a Figura 3. O VMM suporta um número muito grande de dispositivos. Por isso a Virtualização completa utiliza dispositivos genéricos para fazer com que a máquina virtual execute. O fato destes dispositivos não serem específicos faz com que o desempenho da máquina virtual não seja atingido em sua totalidade. A máquina virtual acredita ser executada em um hardware real. Logo, o VMM precisa testar as instruções passadas pela máquina virtual para que em seguida as execute diretamente no hardware. Isso também acontece quando o hardware fornece alguma instrução, pois o VMM primeiro interpreta e testa a instrução antes de passar para a máquina virtual. Além dos aspectos citados, o VMM ainda precisa controlar alguns aspectos relacionados à disputa de recursos, o que causa certa queda de desempenho, visto que os sistemas operacionais foram desenvolvidos para não coexistirem com outros tentando utilizar os mesmos recursos. Figura 4 - Virtualização completa IBM (2006)
  • 23. 23 2.6 PARAVIRTUALIZAÇÃO Segundo Origuela (2006), a técnica de paravirtualização utiliza um conceito parecido com o da virtualização completa. Nesta, o sistema operacional convidado é alterado para interagir com o VMM, para então decidir quais instruções devem ser interpretadas nele ou diretamente no hardware. Os drivers de dispositivos de sistemas paravirtualizados entendem que estão sendo executados como um sistema virtualizado, por isso, durante as requisições, os drivers dos dispositivos da máquina convidada conversam com os drivers reais do sistema operacional principal. De acordo com Jones (2007) a técnica de paravirtualização não simula recursos de hardware, mas ao invés disso oferece uma interface de programação de aplicação (API) para as máquinas virtuais hospedadas, e para isso, o sistema operacional precisará ter sido modificado para suportar tal interface. A paravirtualização é suportada em sistemas que foram modificados para entender que certas requisições, que seriam feitas diretamente ao hardware físico, deverão na verdade ser realizadas primeiramente ao VMM ou Hypervisor, como é chamado muitas vezes, para que o VMM se comunique com o host e aja diretamente no hardware, para então devolver as respostas das requisições. A paravirtualização utiliza o conceito de domínios. Existe um domínio chamado domínio zero, onde reside o sistema operacional que tem acesso direto ao hardware. Este domínio precisa possuir um sistema que foi modificado para suportar paravirtualização como domínio zero, e é através dele que é realizado o gerenciamento das máquinas virtuais. Figura 5 - Paravirtualização Fonte: Uberhip (2007)
  • 24. 24 Além do domínio zero, existe o domínioU, onde residem as máquinas virtuais. Cada máquina virtual que reside em um domínioU também precisa ter sido modificada. Cada domínioU executa uma instância completa de um sistema operacional. Para utilizar a paravirtualização, não é necessária a utilização de hardware com suporte à virtualização, pois os sistemas operacionais já são modificados para suportar esta técnica, conforme ilustra a Figura 4. De acordo com a IBM (2006), a paravirtualização oferece um desempenho muito próximo ao de sistemas não virtualizados. 2.7 VIRTUALIZAÇÃO DE SISTEMA OPERACIONAL De acordo com o arquiteto da Microsoft Chantry (2009), a técnica da Virtualização de sistema operacional utiliza um sistema operacional como sistema base. Os sistemas convidados compartilham os mesmos recursos e drivers do sistema operacional base, mesmo que pareçam computadores totalmente separados, conforme ilustra a Figura 5. Cada sistema operacional convidado terá o seu próprio sistema de arquivos, endereço IP, configurações de servidor e executarão aplicativos totalmente diferentes. Figura 6 - Virtualização de sistema operacional Fonte: Chantry (2009) 2.8 HARDWARE COM SUPORTE À VIRTUALIZAÇÃO Diversas técnicas de virtualização existem hoje e, além disso, muitos softwares são construídos com base em uma técnica. Além da construção de softwares com suporte à virtualização, existem hardwares que são produzidos para auxiliar tais softwares na execução de tarefas essenciais, de acordo com a Intel (2010).
  • 25. 25 A Intel lançou a tecnologia Intel VT (Intel Virtualization Techonlogy) que está presente em diversos processadores para auxiliar softwares de virtualização e, de acordo com a Intel (2010), proporcionar a utilização máxima do sistema por meio de consolidação de ambientes em um único servidor ou PC. Além da Intel VT a empresa AMD possui a tecnologia chamada AMD-V. De acordo com a AMD (2009) a tecnologia foi desenvolvida para aumentar drasticamente o desempenho da aplicação virtualizada, possibilitando também a alternância mais rápida entre máquinas virtuais, para que mais máquinas virtuais possam ser hospedadas por servidor, maximizando os benefícios da virtualização. Os hardwares com suporte à virtualização auxiliam os softwares de virtualização para que os sistemas operacionais não precisem ser modificados para poderem ter um melhor desempenho durante sua execução. Alguns softwares de virtualização funcionam com um bom desempenho apenas quando o hardware possui suporte à virtualização. Entretanto, há softwares que não necessitam de hardware com suporte à virtualização, mas que conseguem um ótimo desempenho durante a execução de máquinas virtuais devido ao fato de os sistemas operacionais terem sido modificados para tal.
  • 26. 26 3 FERRAMENTAS PARA VIRTUALIZAÇÃO Diferentes ferramentas estão disponíveis hoje e cada uma utiliza uma técnica de virtualização diferente. Na Tabela 1, pode-se visualizar as principais ferramentas disponíveis e os tipos de virtualização que utilizam. Cada ferramenta possui seus pontos fortes e fracos, incluindo ferramentas livres e pagas. Tabela 1 – Ferramentas de virtualização Fonte - O autor Ferramenta Tipo Bochs Emulação QEMU Emulação VMWare Virtualização completa Linux KVM Virtualização completa Hyper-V Virtualização completa – Paravirtualização Xen Paravirtualização – Virtualização completa UML Paravirtualização Linux V-server Virtualização de sistema operacional Open VZ Virtualização de sistema operacional 3.1 BOCHS A ferramenta Bochs (que se pronuncia Box) é um emulador de software que não possui interface gráfica. A ferramenta é livre e emula computadores Intel x86. De acordo com a Bochs (2009), o Bochs emula apenas máquinas i386, i486, Pentium, Pentium Pro da Intel e CPUs AMD64, além de periféricos comuns como discos, memória, monitor e dispositivos de rede. A ferramenta foi desenvolvida em C++ e seu código pode ser compilado em basicamente qualquer plataforma, seja em Windows, MacOS X ou em várias versões de Unix. O software foi escrito por Kevin Lawton que ainda o mantém. O Bochs foi criado para emular sistemas operacionais Linux, DOS e Windows 95/98/XP/2000/NT. O fato de ser compatível com diversas plataformas é um ponto forte e ao mesmo tempo fraco em relação a outras máquinas virtuais, visto que os equipamentos como BIOS, placas de vídeo, som e basicamente todos os componentes são emulados através
  • 27. 27 do software, o que faz com que a portabilidade seja maior, mas a velocidade passa a ser menor. 3.2 QEMU De acordo com Bellard (2005), o próprio desenvolvedor do Qemu, o software suporta dois modos operacionais: a emulação em modo de usuário e a emulação em modo de sistema. A emulação em modo de usuário permite que um processo construído para executar em certa CPU possa ser executado em outra, utilizando um conversor dinâmico como técnica para emulação, para que as partes do código sejam convertidas de maneira que o processador execute o conjunto de instruções. A emulação em modo de sistema permite a emulação de um sistema integral, incluindo processador e periféricos de diferentes tipos. [...] o QEMU como um emulador do sistema PC fornece uma extensa variedade de periféricos.[...] Um emulador Vídeo Graphics Array (VGA) de hardware, mouse e teclado PS/2, disco rígido e interface de CD-ROM do Ambiente de Desenvolvimento embarcado (IDE) e emulação de disco flexível. [...] Inclui a emulação para um adaptador de rede NE2000, portas seriais, numerosas placas de som e um controlador Universal Serial Bus (USB).[...] (Jones, 2007) Bellard (2005) também informa que para otimizar a emulação alguns módulos, aceleradores Qemu podem ser instalados fazendo com que o desempenho quase nativo possa ser obtido, permitindo que o código emulado seja executado diretamente na CPU real (do host). A princípio, o Qemu foi desenvolvido para executar um sistema operacional em outro, como um Windows em um Linux ou um Linux em um Windows. Ele pode executar em diversos sistemas operacionais como Linux, Windows e MacOs X. O ponto forte do Qemu é o fato de possuir um conversor dinâmico, rápido e portátil, que traduz as instruções para a CPU convidada vindas da CPU host, fornecendo assim a emulação. O conversor pode fazer cache de trechos de código para minimizar a sobrecarga, tornando-o mais rápido. 3.3 VMWARE A empresa VmWare (2010) fornece uma variedade de ferramentas para virtualização, desde softwares gratuitos para virtualização de desktops e servidores, até
  • 28. 28 plataformas abrangentes de nível empresarial para otimização de data centers e da infraestrutura de TI. As ferramentas gratuitas são limitadas, enquanto as pagas fornecem recursos bem mais avançados. Diversos produtos são disponibilizados pela VmWare (2010), como por exemplo o VmWare Workstation, VmWare Server, VmWare Player, que são ferramentas de virtualização que executam em um sistema hospedeiro. Existe outra plataforma chamada VmWare ESX, ilustrada na Figura 6, que por si mesma é um sistema operacional hospedeiro baseado em Linux. Figura 7 – VmWare ESX Fonte: VmWare (2010) Pelo fato de utilizar virtualização completa, todos os componentes de hardware são virtualizados, e o suporte para todos os dispositivos são fornecidos pelo próprio sistema operacional hospedeiro. O VmWare utiliza drivers genéricos para os dispositivos, chamado de VMDriver. Pelo fato de utilizar dispositivos genéricos, o desempenho das máquinas diminui. De acordo com a VmWare (2010), o desempenho do VmWare ESX chega a ser melhor do que as ferramentas que precisam de um sistema hospedeiro, mas a portabilidade diminui devido a limitações do próprio sistema. O VmWare possui ferramentas com interface gráfica que facilitam a administração das máquinas virtuais existentes. O VmWare faz uso do VMM, que intercepta e testa as instruções passadas pela máquina virtual para poder então executá-las diretamente no hardware. O mesmo acontece quando o hardware fornece alguma instrução, pois o VMM a interpreta e passa para a máquina virtual. Além disso, os recursos da máquina hospedeira são disputados
  • 29. 29 pelas máquinas virtuais, e por isso o VMM também realiza o controle desses recursos, o que causa mais queda no desempenho. 3.4 LINUX KVM De acordo com os desenvolvedores do KVM (2010), KVM significa Kernel- based Virtual Machine. O Linux KVM é um framework de virtualização completa que utiliza as tecnologias de virtualização Intel-VT e AMD-V, que estão nos processadores mais recentes. O KVM é uma ferramenta livre e está presente no Kernel Linux 2.6.20, e é possível executar qualquer sistema operacional sem que nenhuma modificação seja realizada, desde que haja tecnologia de virtualização embutida no processador. Cada máquina virtual é tratada como um processo Linux, por isso pode-se manipular as máquinas com comandos de manipulação de processos. 3.5 HYPER-V Hyper-V é a solução de Virtualização completa Microsoft parecido com as ferramentas VmWare. Além disso, de acordo com a Microsoft (2010), a ferramenta suporta paravirtualização para sistemas operacionais que são modificados para tal. A Microsoft possui o Hyper-V Standalone como sendo o próprio sistema hospedeiro além de possuir a opção de ser executado em um host Windows Server 2008. Quando adquirido o Windows Server 2008 R2, o Hyper-V faz parte do sistema, não sendo necessário adquirir licenças. Para a utilização de alguns recursos, o Hyper-V necessita do System Center Virtual Machine Manager, que necessita de licenças para funcionar. A Microsoft (2010) informa que para o funcionamento do Hyper-V é necessário possuir as tecnologias de aceleração de virtualização nos processadores como Intel VT ou AMD-V. O Hyper-V é uma ferramenta que ainda está em aperfeiçoamento, mas possui alguns benefícios por ser desenvolvido pelo próprio fabricante do Windows, o que traz algumas compatibilidades e facilidades na administração. 3.6 XEN O Xen (2010) é uma ferramenta de paravirtualização que também suporta virtualização completa quando o hardware possui suporte a tecnologia Intel VT ou AMD-V, que foi desenvolvido em um projeto na Universidade de Cambridge, que mais tarde tornou-se a empresa XenSource Inc, e então foi adquirida pela Citrix System em outubro de 2007. O Xen possui um desempenho melhor do que os produtos que utilizam virtualização completa quando o hardware da máquina física não possui suporte a
  • 30. 30 virtualização. Na virtualização completa, algumas tarefas que precisam ser executadas pelas máquinas virtuais não podem ser executadas diretamente no processador, pois são tratadas como um processo na camada de aplicação da máquina hospedeira. Com isso, o VMM intercepta as tarefas, e as executa. Isto causa certa perda de desempenho em hardwares sem suporte à virtualização. Já na paravirtualização, os sistemas operacionais a serem executados, precisam ser modificados para que estas tarefas específicas, que precisariam ser executadas na CPU, possam ser diretamente executadas no VMM, sem haver a tentativa de acesso direto a CPU e sem que o VMM as intercepte, trazendo ganho de desempenho. Uma grande vantagem do Xen é que ele pode executar máquinas virtuais em hardwares que não possuem suporte à virtualização, com um desempenho muito próximo ao da máquina nativa. Apesar disso, os sistemas operacionais precisam ser modificados para funcionarem. Hoje já existem diversos sistemas com suporte ao Xen, como o Linux, FreeBSD e Windows, mas alguns necessitam de tecnologia de hardware Intel VT ou AMD-V para utilizar a virtualização completa, e outros já possuem o código modificado para utilizar paravirtualização. Nas Tabelas 2 e 3 são citados os sistemas operacionais que suportam o Xen como servidor e como máquina convidada. Tabela 2 – Suporte Xen 3.0 Fonte: O autor OS Executar como Dom0 (host) Executar como domU (convidado) Linux 2.6 Sim Sim NetBSD 3.1 Não Sim NetBSD 4.0_Beta2 e atual Sim Sim FreeBSD 5.3 Não Sim FreeBSD 7 Não Sim Solaris 10 Não Sim Sistemas Operacionais não Modificados Não Sim, somente quando o hardware possui suporte Intel VT ou AMD-V
  • 31. 31
  • 32. 32 Tabela 3 – Suporte Xen 2.0 Fonte: O autor Sistema operacional Executar como Dom0 (host) Executar como domU (convidado) Linux 2.4 Sim Sim Linux 2.6 Sim Sim NetBSD 2.0 Não Sim NetBSD 3.0 Sim Sim Plan 9 Não Sim FreeBSD 5 Não Sim De acordo com a Xen (2008), cada máquina virtual é chamada de domínio. Existem dois tipos de domínio: o domínio 0 (chamado de domain0 ou dom0), que é o domínio de controle, e o domínio U (chamado domainU ou domU), que é o domínio sem privilégios, ou seja, o sistema operacional convidado. Cada domínio executa uma instância completa do sistema operacional. Figura 8 – Componentes do Xen Fonte: Carissimi (2008)
  • 33. 33 Para que o Xen ofereça suporte tanto à virtualização completa quanto à paravirtualização, é utilizado o conceito dos domínios explicado anteriormente, com algumas modificações. O Xen reconhece os domínios U-PV, como domínios paravirtualizados e U-HVM (hosted virtual machines) como domínios virtualizados. Os domínios U-PV são os domínios que possuem os sistemas operacionais modificados, que sabem que existem outras máquinas virtuais e possuem drivers específicos para acesso à rede e disco e, além disso, sabem como interagir com o domínio 0. Os domínios U-HVM não são modificados, ou seja, não sabem que existem outras máquinas virtuais e por isso não possuem drivers específicos para o acesso a recursos, necessitando do hardware com suporte à virtualização para que o desempenho não caia, conforme ilustra a Figura 7. De acordo com a Xen (2008), para que o domínio U-HVM funcione, ele faz o uso do Qemu (o emulador de software), e os recursos de hardware que são disponíveis para o domínio são os mesmos oferecidos pelo Qemu. 3.7 UML UML (User mode Linux) permite que um sistema operacional Linux execute outro sistema operacional Linux como convidado através da paravirtualização. De acordo com Dike (2010), cada sistema operacional Linux convidado existe como um processo no host Linux. Isto permite que vários Kernels de versões diferentes possam ser executados em uma única versão de Kernel Linux, conforme ilustra a Figura 8. Figura 9 – User mode Linux Fonte: IBM (2006) Um dos grandes benefícios e foco do UML é poder realizar testes em versões de Kernels Linux diferentes sem prejudicar o host Linux principal. O UML também fornece mais recursos de hardware e software do que os da máquina física (host).
  • 34. 34 Jones (2007) explica que os Kernels convidados executam no espaço de aplicação, e para funcionarem precisam ter sido compilados para tal, enquanto o Kernel Host reside diretamente no hardware.
  • 35. 35 4 ASTERISK O Asterisk é um software livre que implementa recursos de PBX completo e muitas outras funções através da tecnologia de VoIP. Mark Spencer da Digium Inc. foi quem iniciou o projeto por volta do ano de 1999. Inicialmente o Asterisk foi desenvolvido para implementar apenas recursos em software como um PBX de código aberto, mas de acordo com Davenport (2010), hoje o Asterisk implementa não apenas recursos de sistemas PBX, mas também gateways VoIP, sistemas de Call Center, pontes de conferência, servidores voicemail e todos os tipos de aplicativos que envolvam comunicação em tempo real. O sistema roda em servidores Linux e faz VoIP através de três diferentes protocolos. De acordo com a Asterisk Brasil (2010), o Asterisk pode se integrar a praticamente todos os padrões de telefonia utilizando hardware de baixo custo. Ele é um servidor de comunicação que detém todos os níveis baixos de detalhes para envio e recebimento de dados utilizando alguns diferentes tipos de protocolos. Os protocolos utilizados pelo Asterisk são protocolos abertos como o SIP, MGCP e IAX, os quais realizam a sinalização das chamadas telefônicas na rede IP. Após a instalação do Asterisk, um servidor de comunicação passa a existir, mas para que ele realmente se comunique, é preciso criar aplicativos de comunicação realizando e alterando configurações, que o fará funcionar da maneira planejada. Estes aplicativos de comunicação são construídos através de scripts, arquivos de configuração, gravações de áudio, banco de dados, serviços web, etc. Para que um aplicativo de comunicação funcione, é preciso que o servidor de comunicação esteja conectado a serviços de comunicação como VoIP ou PSTN. Para que as pessoas acessem o sistema de comunicação, é preciso ter números de telefones ou URLs VoIP que enviem chamadas ao servidor. 4.1 SIP De acordo com a IETF (2010), o SIP é um protocolo IETF (RFC 2543, 1999) de aplicação parecido com o HTTP ou SMTP, que segue o modelo requisição-resposta para iniciar sessões de comunicação VoIP e outras sessões de texto e multimídia, como mensagens instantâneas, vídeo, jogos online e outros serviços. Para comunicação, ele utiliza a porta 5060 tanto UDP como TCP. Alguns recursos que o protocolo oferece na parte de telefonia são: transferências de chamada, conferências telefônicas e chamadas em espera. Por ser um protocolo flexível, é possível adicionar mais recursos ao SIP.
  • 36. 36 4.2 MGCP De acordo com a Arango (1999), o MGCP também é um protocolo do grupo IETF que integra a arquitetura SS7 em redes VoIP. A arquitetura SS7 é uma rede de pacotes que se agrega à rede de telecomunicação, adicionando novas funcionalidades e serviços que estão presentes em centrais telefônicas. O SS7 é quem possibilita a comunicação de centrais telefônicas de maneira confiável e rápida. O MGCP possuiu um agente de chamada, um MG (Media Gateway), que é o responsável pela conversão de sinais entre circuitos, e pelo menos um SG (Signaling Gateway) conectado a um PSTN. 4.3 IAX De acordo com Guy (2009), o IAX é um protocolo desenvolvido para estabelecer conexão entre servidores Asterisk, que também já está presente em telefones VoIP. Ele foi desenvolvido pela Digium Inc., que é a empresa desenvolvedora do Asterisk. O IAX é parecido com o protocolo SIP citado anteriormente, com a diferença de que faz uso de uma única porta UDP de número 4569. O IAX já está na versão 2, mais conhecido por IAX2. Um dos grandes benefícios do IAX é que ele suporta entroncamento de chamadas, ou seja, é possível unir chamadas que se entroncaram em um único conjunto de pacotes e entregar informações para mais de uma chamada ao mesmo tempo.
  • 37. 37 5. LINGUAGENS DE PROGRAMAÇÃO Linguagem de programação é um conjunto de regras que são utilizadas para definir um programa para ser utilizado no computador. Existem alguns tipos de linguagens: alto nível, nível intermediário ou baixo nível. De acordo com Carter (2002, p.46), a linguagem de baixo nível é uma linguagem em que o código é executado diretamente pelo processador. É formada por zeros (0) e uns (1). Por isso também é chamada de linguagem binária ou de máquina. A linguagem de nível intermediário é uma linguagem em que os códigos fonte são chamados de mnemônicos (assembly) onde cada instrução de máquina tem uma representação em texto (como ADD, SUB, ou LOAD). A linguagem de nível intermediário precisa ser transformada em linguagem de baixo nível, por isso era necessário um montador que realizasse a conversão. Tabela 4 – Tipos de linguagens Fonte: O autor Linguagem Compilada/Interpretada ADA Compilada BASIC Interpretada C Compilada C++ Compilada Cobol Compilada Fortran Compilada Java Intermediária (híbrida) MATLAB Interpretada (híbrida) LISP Intermediária (híbrida) Pascal Compilada PHP Interpretada Prolog Interpretada Prolog Interpretada Perl Interpretada Lua Interpretada
  • 38. 38 A linguagem de alto nível é uma linguagem que é mais facilmente entendida pelo ser humano. Antigamente a programação era bem tediosa, pois para executar operações um pouco mais complexas eram necessárias muitas instruções e, além disso, as instruções disponíveis eram diferentes de máquina para máquina. Com isso surgiram as primeiras linguagens de alto nível como Pascal, COBOL e C. Através da linguagem de alto nível é possível desenvolver programas em muito menos instruções, ou seja, seu desenvolvimento é muito mais rápido do que era antigamente. Para que a linguagem de alto nível seja entendida pela máquina é preciso de alguém que a traduza. Existem algumas maneiras para realizar a tradução, seja através de um compilador ou interpretador. Na tabela 4, estão listadas algumas linguagens importantes e seus respectivos tipos. 5.1 LINGUAGENS INTERPRETADAS Linguagem interpretada é uma linguagem de programação que necessita de um interpretador para ser executada. O código-fonte de uma linguagem interpretada só será entendido pela máquina se houver o interpretador para traduzir a respectiva linguagem. De acordo com Louden (2004, p.04), um interpretador é um tradutor de linguagens, assim como o compilador. A diferença é que o interpretador executa o programa-fonte de imediato, traduzindo as instruções de programação conforme são lidas pelo programa, em vez de gerar um código-objeto que seja executado após o término da tradução. Figura 10 - Linguagem interpretada Fonte: Caldas (Slide 14) De acordo com Sebesta (2002, p. 154), algumas linguagens são tipicamente interpretadas, outras utilizam os dois métodos (compilação e interpretação) para serem executadas. Um interpretador compartilha muitas de suas operações com os compiladores, podendo existir compiladores híbridos que ficam entre os interpretadores e compiladores. Se uma linguagem for compilada e o código gerado não for entendido
  • 39. 39 pelo sistema operacional e processador, necessitando de que algum mecanismo a interprete, esta linguagem também será uma linguagem interpretada. 5.1.1 LINGUAGEM DE EXTENSÃO OU SCRIPT Linguagem de extensão também pode ser chamada de linguagem de script. Essas linguagens normalmente controlam programas, pois são executadas dentro deles. De acordo com a Stanford University (2004), as linguagens de extensão são muito utilizadas em sistemas operacionais e também em muitos jogos. O Linux é um sistema operacional que utiliza bastante a linguagem de extensão para controlar aplicativos e rotinas do próprio sistema operacional. O Windows também utiliza linguagem de extensão. Um exemplo disso são os scripts VBS. Alguns jogos utilizam a linguagem de extensão para poder controlar ações de personagens. Pode-se dizer que toda linguagem de extensão é uma linguagem interpretada, mas que nem toda linguagem interpretada é uma linguagem de extensão. As linguagens de extensão são classificadas segundo sua complexidade: - Linguagem de Macro: São utilizadas para tarefas de automação com abrangência mais limitada. - Linguagens Embutidas: Permitem o acesso programável aos serviços da aplicação hospedeira (ou principal). São linguagens mais completas e mais complexas que a anterior. Figueiredo (2002) informa que a adoção de uma linguagem de extensão é um poderoso recurso no desenvolvimento de softwares, pois permite que muitos aspectos da aplicação hospedeira sejam controlados externamente. Esse controle consiste na edição de arquivos textos facilmente modificados pelo desenvolvedor sem a necessidade de recompilar a aplicação, tornando o desenvolvimento mais rápido e muito mais flexível. Uma linguagem de extensão deve ter como foco a produtividade do programador. Segundo Proebsting (2002), um dos problemas mais sérios no desenvolvimento de uma linguagem de programação é em como melhorar a produtividade do programador. Os hardwares atualmente possuem um poder de processamento suficientemente grande para não precisar de otimização massiva da linguagem internamente.
  • 40. 40 5.2 LINGUAGENS COMPILADAS Linguagem compilada é uma linguagem onde o código fonte é executado diretamente pelo sistema operacional ou pelo processador. O código é traduzido para executar um conjunto de regras ou instruções, e esse processo chama-se compilação. Para isso, é utilizado um software próprio, chamado compilador, que efetua a tradução para linguagem de baixo nível, como linguagem de montagem ou código de máquina. De acordo com Louden (2004, p. 13), a geração do código é muito complexa, pois depende das informações da estrutura do ambiente de execução, através de tentativas de otimizar ou aperfeiçoar a velocidade ou tamanho do código fonte. A linguagem compilada elimina essa fase em vários passos, utilizando estruturas de dados intermediários. Após a compilação, cria-se um programa executável, armazenando as informações e não é necessário a recompilação. Figura 11 - Linguagem compilada Fonte: Caldas (Slide 14) A vantagem é que o usuário nunca terá acesso ao código fonte, evitando assim a alteração e danificação do programa.
  • 41. 41 6 METODOLOGIA Neste capítulo serão apresentados a metodologia adotada e informações necessárias para atingir o objetivo proposto no trabalho, além de justificar a escolha das tecnologias utilizadas. Esta parte do trabalho foi dividida em etapas que ajudarão a construir um ambiente com suporte à paravirtualização, instalar e configurar o Asterisk em máquina virtual, desenvolver uma linguagem que possa ser interpretada pelo Asterisk, utilizar a API do Asterisk para que entenda a linguagem criada, e a execução de testes com VoIP utilizando o ambiente e linguagem criados. As etapas necessárias estão divididas da seguinte forma: 1. Ambiente virtualizado: - Escolha da tecnologia de virtualização que será utilizada; - Criação e configuração do ambiente virtualizado; - Instalação e configuração do Asterisk. 2. Linguagem interpretada: - Desenvolvimento da linguagem interpretada; - Fazer a integração da linguagem com o Asterisk através da API do próprio Asterisk. 3. Testes finais: - Realizar testes com VoIP utilizando a linguagem interpretada no Asterisk paravirtualizado. 6.1 VIRTUALIZAÇÃO A paravirtualização foi escolhida como técnica a ser utilizada para a implementação do ambiente devido aos benefícios que ela apresenta. Como principais benefícios pode-se citar que a paravirtualização pode ser implementada em qualquer máquina da plataforma x86 sem necessitar de hardware com suporte à virtualização (como Intel-VT ou AMD-V), por isso mais tipos de máquinas, inclusive máquinas mais antigas, poderão ser utilizadas para a aplicação da técnica. A ferramenta a ser utilizada para aplicação da técnica de paravirtualização será o Xen com o sistema operacional Linux distribuição Open Suse, pois apresenta algumas características que facilitarão a criação do ambiente como: um ótimo desempenho mesmo utilizando máquinas sem hardware com suporte à virtualização e máquinas de hardware comuns, software de código aberto, o que facilita ainda mais o acesso ao
  • 42. 42 software, além disso, já existem diversos sistemas operacionais com suporte a paravirtualização e ao Xen. O Xen será instalado e configurado no sistema operacional Linux Open Suse como domínio 0. Uma máquina virtual será criada dentro do Xen. A máquina virtual também possuirá o sistema operacional Linux Open Suse. Nesta nova máquina virtual será instalado o software Asterisk em preparação para os próximos passos. 6.2 LINGUAGEM INTERPRETADA O desenvolvimento do Interpretador, aqui chamado de dfn, consistirá em uma linguagem feita em “C” para aplicações em “C/C++” que funcionará como extensão da aplicação hospedeira que no caso será o Asterisk. Essa abordagem permite que a aplicação seja expandida sem a necessidade de alteração de linha de código. Toda a nova lógica, portanto, será implementada na linguagem aqui proposta. A integração entre o interpretador e o Asterisk ocorrerá mediante o uso de funções específicas, previamente definidas, conforme o documento "Asterisk Coding Guideline" disponível no site do fabricante Asterisk (2010). 6.3 TESTES FINAIS Após a criação do ambiente paravirtualizado, o desenvolvimento da linguagem interpretada e configuração do Asterisk para entender a linguagem, será necessário juntar os dois primeiros passos citados na introdução do capítulo 6 e realizar testes no ambiente criado utilizando a linguagem desenvolvida. Estes testes envolverão o desenvolvimento de um código utilizando a linguagem criada que substituirá arquivos de configuração do Asterisk. Estes arquivos de configuração contêm instruções sobre tomada de decisão relacionados ao VoIP. Em vez de o Asterisk ler o arquivo de configuração padrão (extensions.conf), ele lerá o arquivo .dfn que será o motor da linguagem aqui proposta. Para isso o Asterisk precisará entender a linguagem, ou seja, interpretá-la. O Asterisk já deverá ter sido configurado para interpretá-la de acordo com o que foi mencionado no item 6.2. Ao final deste trabalho se chegará ao resultado da viabilidade do uso ou desenvolvimento de uma linguagem interpretada (extensível) para permitir maior flexibilidade na parametrização de aplicativos que necessitem do uso de configuração para o seu funcionamento e de que a paravirtualização garante um SLA elevado uma vez que na indisponibilidade de um hardware, outro poderá assumir como hospedeiro
  • 43. 43 mantendo o funcionamento dos serviços sem a necessidade de reinstalação de uma nova máquina.
  • 44. 44 7 DESENVOLVIMENTO A partir deste capítulo será abordada toda a estrutura de criação do ambiente paravirtualizado, assim como os detalhes do desenvolvimento da linguagem interpretada para sistema multi-plataforma. Para isso, foram necessários o estudo de tecnologias necessárias para implementação do Asterisk, para a criação de uma linguagem interpretada e de um ambiente virtualizado estável. 7.1 CONFIGURAÇÃO DO AMBIENTE Para a implementação do Xen e Asterisk em preparação para os testes com a linguagem criada será utilizada uma máquina Intel QuadCore Q9400 2.66GHz, 4GB de memória RAM, 2 HDs de 1TB em RAID-1, com sistema operacional Linux distribuição Open Suse 11.3. 7.2 DETALHES DE IMPLEMENTAÇÃO DA PARAVIRTUALIZAÇÃO Para implementação das máquinas virtuais foi criada uma máquina real com o sistema operacional Linux distribuição Open Suse 11.3 Português e interface KDE. Este sistema é o sistema que chamamos de domínio 0 (domain0 ou dom0), que é o domínio de controle, conforme explicado no item 3.6. É o domínio que possui o sistema Xen para o controle e alocação das máquinas virtuais. O OpenSuse 11.3 possui o Xen pré-instalado em um pacote que contém o Xen Hypervisor. Para instalar o Xen Virtualization é preciso selecionar no menu de seleção de Software e tarefas de sistema a opção Servidor hospedeiro de máquina virtual Xen, conforme mostra a figura 11. Figura 12 – Instalação Xen Fonte: O autor O particionamento foi dividido da seguinte forma: -Volume de Swap /dev/sda1 - Volume Raíz /dev/sda2 com ext4 - Volume /dev/sda3 para /home com ext4
  • 45. 45 Para instalar o Hypervisor e Ferramentas foi necessário selecionar a opção “instalar o Hypervisor e suas ferramentas” após a instalação do sistema operacional conforme Figura 12. Figura 13 – Instalando o Hypervisor e Ferramentas 1 Fonte: O autor Ao instalar o Hypervisor e suas ferramentas é retornada a mensagem informando que o servidor VM (domínio 0) foi configurado com sucesso e que estará pronto para a criação de máquinas virtuais. Domínio 0 configurado e pronto para iniciar (ver figura 13): Figura 14 – Domínio 0 configurado Fonte: O autor Após a instalação foi realizada a criação da máquina virtual no domínio U-PV, que possui o sistema operacional modificado para executar a paravirtualização.
  • 46. 46 Abaixo está o exemplo do arquivo de configuração utilizado e modificado para a manipulação da máquina virtual chamado vm_xen_tcc.conf localizado em /images/config/: # # Arquivo de configuração da máquina virtual a ser usada no trabalho # kernel = "/images/TCC/boot/vmlinuz-xen" ramdisk = "/images/TCC/boot/initrd-xen" builder='linux' memory = 512 name = "TCC_VM_DFN" #uuid = "06ed00fe-1162-4fc4-b5d8-11993ee4a8b9" # Number of Virtual CPUS to use, default is 1 vcpus = 1 vif = [ 'mac=00:16:3e:00:00:11, bridge=br0' ] disk = [ 'file:/images/TCC/vdisks/sda_vdisk_12GB.img,xvda,w', 'file:/images/TCC/vdisks/sdb_vdisk_16GB.img,xvdb,w' ] root = "/dev/xvda2" vfb = [ 'vnc=1,vnclisten=0.0.0.0,vncunused=1,vncpasswd=reurbanisatus' ] # Set root device. #root = "/dev/hda1" # Extra arguments to pass to the kernel. extra = "xencons=xvc console=xvc0 video=tty" #on_poweroff = 'destroy' 7.3 INSTALAÇÃO ASTERISK O Asterisk lê as regras de chamadas e discagem a partir do arquivo "extensions.conf". A linguagem dfn substituirá a configuração do "extensions.conf". Na prática, o mecanismo do Asterisk será instruído a ler o arquivo "extensions.dfn" que conterá toda a lógica de atendimento e regras de discagem. As contas dos usuários continuarão a ser configuradas no arquivo sip.conf no caso de uso do protocolo SIP. Para o IAX2, o arquivo deverá ser o iax2.conf.
  • 47. 47 Esse mecanismo não será alterado e não terá interação com a linguagem propriamente dita, uma vez que esse faz parte do processo de autenticação do Asterisk, uma camada anterior à execução do script de atendimento em dfn. 7.3.1 INTERAÇÃO ENTRE O ASTERISK E O MÓDULO DA LINGUAGEM DFN A implementação ou interface entre a linguagem dfn e o asterisk será feita no código pbx_dfn.c. O módulo final é o pbx_dfn.so e o mecanismo obedece o fluxo conforme as figuras 14 e 15. Figura 15 – Processo de inicialização Fonte: O autor Figura 16 – Tratamento de chamada Fonte: O autor
  • 48. 48 Figura 17 – Compilação do módulo Fonte: O autor A figura 17 mostra a compilação do módulo do Asterisk utilizando o arquivo pbx_dfn e a Figura 18 exibe o diretório de módulos com o arquivo pbx_dfn.so. Figura 18 – Diretório de módulos do Asterisk Fonte: O autor
  • 49. 49 O Asterisk lerá o arquivo extensions.dfn onde todas as regras de atendimento estarão declaradas. Como as regras de atendimento do Asterisk são baseadas em contexto, a linguagem dfn tratará essa regra como regra de entrada e executará as funções internas do Asterisk responsáveis pelo controle de chamadas, geração de CDRs, desligamento de chamadas, etc. Abaixo segue o trecho do código do pbx_dfn.c das partes mais importantes responsáveis pela integração entre o Asterisk e a linguagem dfn. A API do Asterisk trabalha com as funções load_module, unload_module, reload e AST_MODULE_INFO. Essas quatro funções são o coração da integração entre qualquer modulo e o Asterisk. Quando o modulo é carregado, o asterisk lê os parâmetros passados à macro AST_MODULE_INFO. A partir deste instante cada função é executada conforme a ação do Asterisk. Deve-se, obrigatoriamente, declarar o nome o arquivo padrão na variável config, o nome do módulo na variável registrar, todas como static para ponteiro do tipo char. static char *config = "extensions.dfn"; static char *registrar = "pbx_dfn"; A função load_module é a responsável pela carga do módulo da linguagem. Quando o módulo é carregado, a função deverá retornar 2 possíveis valores declarados como constantes (#define): AST_MODULE_LOAD_SUCCESS no caso de sucesso na carga ou AST_MODULE_LOAD_DECLINE para a situação de exceção ou erro no módulo. static int load_module(void) { int res; if ((res = load_or_reload_dfn_stuff())) return res; if (ast_register_switch(&dfn_switch)) { ast_log(LOG_ERROR, "Unable to register DFN Language Extension Modulen");
  • 50. 50 return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; } A função unload_module tem como objetivo a remoção do módulo da memória quando solicitado pelo usuário via console ou por situação de exceção interna do Asterisk. Duas outras funções internas devem ser chamadas: ast_context_destroy, que informa ao asterisk qual modulo será removido ou desregistrado e a função ast_unregister_switch que receberá o ponteiro da função do motor da linguagem propriamente dita. static int unload_module(void) { ast_context_destroy(NULL, registrar); ast_unregister_switch(&dfn_switch); dfn_free_extensions(); return 0; } A função reload tem como objetivo chamar a função load_or_reload_dfn_stuff que apenas remove e recarrega a linguagem dfn. static int reload(void) { return load_or_reload_dfn_stuff(); } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "DFN Language Extension Module", .load = load_module, .unload = unload_module, .reload = reload, );
  • 51. 51 Abaixo segue exemplo do arquivo de configuração dos módulos do Asterisk juntamente com os comentários explicativos de cada parte do arquivo e o arquivo sip.conf: [modules] ; autoload habilitado, instrui o Asterisk a carregar todos os arquivos *.so que encontrar em /var/lib/asterisk/modules autoload=yes ; Cada módulo precisa ser carregado antes do núcleo do Asterisk ser inicializado. ; ; A linha abaixo só deverá ser descomentada se o autoload for igual a "no". ;load => pbx_dfn.so ; Como o autoload está habilitado, caso não se pretenda carregar o módulo da linguagem dfn, ; deve-se remover o comentário da linha abaixo ;noload => pbx_dfn.so Figura 19 – Arquivo sip.conf Fonte: O autor 7.4 DESENVOLVIMENTO DA LINGUAGEM INTERPRETADA PARA SISTEMA MULTI-PLATAFORMA A linguagem aqui proposta, chamada de dfn, implementa as construções fundamentais para definição de controle de fluxo como if, elseif, else, endif, while, do, endwhile, repeat, until, funções, e tipos definidos de dados. Trata-se ainda de uma linguagem com tipagem dinâmica. As próximas seções procuram tratar da estrutura da linguagem, tipos de dados,
  • 52. 52 sintaxes, etc. 7.4.1 VARIÁVEIS E TIPOS As varáveis do dfn deverão conter pelo menos um caractere e deve ser iniciado por uma letra obrigatoriamente, os caracteres seguintes poderão ser outras letras, números e sublinha. Letras maiúsculas e minúsculas são diferentes. Exemplo: Nomes válidos de variáveis: a=12 a21 = “Teste” meuValor=51 Minha_Variavel=”Ok” Nomes inválidos de variáveis: _12=21 21=22 *valor=12 Esses nomes não são admitidos como válidos no contexto da linguagem dfn. A linguagem possui os seguintes tipos de variáveis, sendo que sua conversão é automática, o que lhe confere uma tipagem dinâmica: Tipo null - esse tipo indica um valor indefinido. Por padrão todas as variáveis não declaradas são do tipo null, podendo, a partir desse conceito, verificar se uma variável foi ou não declarada no sistema. Tipo numeric - são variáveis que contêm somente números armazenados. Tipo string - São cadeias de caracteres contendo letras, números e caracteres especiais como "@", "%", etc. Tipo array - São variáveis com índice numérico onde cada índice aponta para a posição onde o valor é armazenado. Tipo hash - São arrays associativos, ou seja, o índice pode ser qualquer caractere ou cadeia de caractere, numérico ou string. Tipo function - Esse tipo de dado compreende as funções declaráveis pelo programador na linguagem. Toda função criada pelo usuário deverá ser iniciada
  • 53. 53 pelo comando function, seguido do nome da função com os seus parâmetros entre parêntesis e separado por vírgula (caso haja mais de um). 7.4.2 ATRIBUIÇÕES Para atribuição deve-se usar o sinal de igual simples “=” entre a variável e o valor. A simples atribuição já é suficiente para a própria declaração da variável. A atribuição pode ser simples ou múltipla. Exemplo: Variável = Valor O “Valor” pode ser numérico, string, array ou qualquer outro tipo de dados permitido pela linguagem. Já a atribuição múltipla pode ser vista no exemplo a seguir: var1, var2, var3 = "Universidade Anhembi Morumbi", 1231, {1,2,3,"Eu sou um valor de um array"} No caso acima, a variável var1 é do tipo string, a var2 do tipo numérico e a var3 é um array de 4 elementos. A atribuição múltipla permite a troca de valores armazenados em uma única linha. Exemplo: var1 = "Teste1" var2 = "Teste2" # Resultado var1="Teste1" e var2="Teste2" – Aqui é um comentário print( "var1=",var1, " var2=", var2 ) # Faz a troca var1, var2 = var2, var1 # Resultado var1="Teste2" e var2="Teste1" print( "var1=",var1, " var2=", var2 ) 7.4.3 OPERADORES ARITMÉTICOS E RELACIONAIS Os operadores aritméticos são: adição, subtração, multiplicação e divisão. Exemplos: a = 6/3 b = 2*10 c = 5-1 d = 20+9 Os operadores relacionais disponíveis são: < Menor que > Maior que <= Menor ou igual a >= Maior ou igual a
  • 54. 54 == Igual a != Diferente de 7.4.4 ORDEM DE PRECEDÊNCIA DOS OPERADORES Os operadores têm a ordem de precedência usual. Essa ordem pode ser mudada com o uso de parênteses A lista abaixo apresenta os operadores, em ordem decrescente de precedência: ^ not -(unário) * / + - 7.4.5 COMENTÁRIOS A linguagem provê recurso de inserção de comentários. Dessa forma o código poderá ser comentado conforme a necessidade do programador. Para isso deverá ser usado o caractere “#”. Exemplo: # Isso é um comentário Variavel=123 # Comentando o código. A partir do # a linguagem vai ignorar o trecho até o fim de linha (n) 7.4.6 FUNÇÕES DA LINGUAGEM Para criação da linguagem foi necessário definir e criar as funções de manipulação de string, conversão de tipos e funções básicas. 7.4.6.1 FUNÇÕES DE MANIPULAÇÃO DE STRING Função strlen( str ) DESCRIÇÃO Informa o tamanho de uma string. ARGUMENTOS str string a ser medida RETORNO Retorna o número de caracteres presentes na cadeia de caracteres. EXEMPLO print(strlen("Universidade Anhembi Morumbi")) # imprime o valor 28.
  • 55. 55 Função strlower( str ) DESCRIÇÃO Todas as letras maiúsculas passadas na variavel str são trocadas pelas minúsculas correspondentes. ARGUMENTOS str string a ser transformada RETORNO Retorna a string transformada. EXEMPLO print(strlower("Teste")) # Imprime teste. Função strupper( str ) DESCRIÇÃO Todas as letras minúsculas passadas na variável str são trocadas pelas maiúsculas correspondentes. ARGUMENTOS str string a ser transformada RETORNO Retorna a string transformada. EXEMPLO print(strlower("Teste")) # Imprime TESTE. 7.4.6.2 FUNÇÕES DE CONVERSÃO DE TIPOS Função tonumber( var ) DESCRIÇÃO Tenta converter a variavel var em um valor numérico. ARGUMENTOS a expressão a ser transformada em valor numérico RETORNO Se for possível a conversão, retornará o valor numérico, caso contrário retornará <null> EXEMPLO print(tonumber("23 "), tonumber("7.1 X"), tonumber(22))
  • 56. 56 # imprime os valores: 23, <null>, 22 Função tostring( var ) DESCRIÇÃO Tenta converter a variável var em um valor string. ARGUMENTOS a expressão a ser transformada em valor string RETORNO O correspondente em string EXEMPLO print(tostring( 22 )) # imprime os valores: "23" 7.4.7 CONTROLE DE FLUXO E LAÇOS ITERATIVOS Foi necessário a criação de controles de fluxo e laços iterativos que serão descritos a seguir. 7.4.7.1 TOMADAS DE DECISÃO COM IF O comando para tomada de decisão da linguagem DFN é o if. Sua forma é: if expr then bloco endif ou if expr then bloco1... else bloco2... endif ou ainda if expr1 then bloco1 elseif expr2 then bloco2
  • 57. 57 ... elseif expr N then bloco N else bloco N+1 endif 7.4.7.2 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO INÍCIO (WHILE) A linguagem DFN possui duas opções para construção de laços iterativos, o comando while permite que a tomada de decisão seja no inicio antes de entrar no laço. Sua forma geral é: while expr do bloco endwhile Isto é, enquanto a expressão expr produzir um valor diferente de null e, portanto, verdadeiro, os comandos do bloco são executados. Considere o código abaixo que calcula o fatorial de um número armazenado na variável n: fat = 1 i = n while i > 0 do fat = fat * i i = i – 1 endwhile Ao final da execução do código acima, fat armazena o valor do fatorial de n e i armazena o valor zero. 7.4.7.3 LAÇOS ITERATIVOS COM TOMADA DE DECISÃO NO FIM (REPEAT/UNTIL) Este tipo de laço é implementado pelo comando repeat/until. A validação da condição é feita após o bloco ser executado por, pelo menos, uma vez. Sua forma geral é: repeat bloco until expr O mesmo exemplo do fatorial acima pode ser reescrito usando o repeat/until conforme a seguir: fat = 1 i = 1
  • 58. 58 repeat fat = fat * i i = i + 1 until i > n 7.4.8 ANALISADOR DE EXPRESSÃO O analisador de expressão adotado na linguagem foi baseado nas ferramentas bison com gerador de parser em conjunto com o gerador de analisador sintático flex a partir da gramática previamente definida. O código resultante foi modificado para otimização da linguagem. gerando dois fontes: y_tab.c e lex_yy.c, a implementação das funcionalidades foram escritas nos demais arquivos "C". A função de entrada é a dfn_execfile, ela recebe o ponteiro para o arquivo a ser executado e chama a função dfn_parse() que por sua vez chama o yyparse() que realiza toda a tradução ou interpretação do código junto com a função dfn_execute(). O trecho da função yyparse() é extremamente grande, assim como a dfn_execute(), e podem ser vistos no apendice deste documento. Segue o trecho responsável pela execução do arquivo fonte dfn: int dfn_execfile(char *filename) { int x, y; y = dfn_openfile(filename); if (y) return 1; x=dfn_parse(); if( x ){ dfn_closefile(); return 1; } dfn_closefile(); return 0; } Função dfn_parse(void)
  • 59. 59 int dfn_parse(void) { Byte *initcode = maincode; err = 0; if (yyparse() || (err == 1)) return 1; *maincode++ = HALT; if (dfn_execute(initcode)) return 1; maincode = initcode; return 0; } 7.5 IMPLEMENTAÇÃO DA LINGUAGEM INTERPRETADA NO SISTEMA PARAVIRTUALIZADO O ambiente final criado para implementação e utilização da linguagem desenvolvida nos capítulos anteriores é exemplificado através da figura 20 com uma máquina host que porta a VM com o Asterisk instalado e configurado para utilizar a linguagem proposta interligada a telefones através de um switch e um aparelho ATA. Figura 20 – Topologia final Fonte: O autor
  • 60. 60 Figura 21 – Módulo carregado com sucesso Fonte: O autor Figura 22 – Módulo não carrega sem extensions.dfn Fonte: O autor
  • 61. 61 A figura 21 mostra que os módulos do Asterisk foram carregados com sucesso utilizando a linguagem DFN. A figura 19 mostra que o módulo foi carregado com sucesso e que o Asterisk está pronto para fazer e receber ligações. A figura 20 mostra que não é possível carregar os módulos do Asterisk sem utilizar o arquivo extensions.dfn. Figura 23 – CDR Fonte: O autor A figura 23 mostra o registro da chamada, também conhecido como CDR da ligação de teste realizada. Foram realizados testes simples de chamada entre dois ramais 4001 e 4002 onde o asterisk executou o código abaixo: arquivo: extensions.dfn Código: contexto = getcontext() # Obtém o contexto da ligação que está entrando exten = getexten() if contexto == "from-internal" then Dial(SIP/exten,50,RTt) # Encaminha a chamada para o Ramal obtido da variável extena endif
  • 62. 62 Figura 24 – Ligação realizada Fonte: O autor A figura 23 mostra que o teste com o arquivo .dfn foi realizado com sucesso.
  • 63. 63 8 CONCLUSÃO Levando-se em conta o que foi observado, pode-se concluir que uma linguagem de programação interpretada (extensível) facilita a parametrização de aplicativos que necessitam do uso de configuração para seu funcionamento, assim como é capaz de permitir a inclusão de novas funcionalidades ao aplicativo. A linguagem desenvolvida neste trabalho demonstrou que, apesar da dificuldade, em função de sua complexidade, para criar e integrá-la a um aplicativo hospedeiro, é possível e recomendável o seu uso, pois uma vez agregada esta funcionalidade ao hospedeiro, a linguagem embarcada expande a capacidade de funcionamento do aplicativo em si. O ambiente criado utilizando a paravirtualização demonstrou que é possível garantir um SLA elevado, uma vez que na indisponibilidade de um hardware, outro poderá assumir como hospedeiro de uma cópia da máquina paravirtualizada. Como trabalhos futuros pode-se apontar o estudo e criação de um ambiente altamente disponível (cluster) utilizando a paravirtualização como plataforma e o Asterisk como software hospedeiro. Além disso, pode-se realizar trabalhos relacionados a testes de desempenho utilizando paravirtualização e virtualização completa com hardwares que utilizam tecnologias Intel-VT ou AMD-V. A linguagem aqui proposta, possui potencial para a sua ampliação em trabalhos futuros como a implementação da geração dos CDRs para ambiente de telefonia VoIP. Trata-se de um recurso importante, pois os CDRs são os registros das chamadas realizadas em um ambiente de telefonia.
  • 64. 64 REFERÊNCIAS BIBLIOGRÁFICAS AMD. Mais eficiência na plataforma de virtualização. Disponível em: <http://www.amd.com/br- pt/Processors/ProductInformation/0,,30_118_8796_14287,00.html>.Acesso em: 25 maio 2010. ARANGO, M. Media Gateway Control Protocol (MGCP). Disponível em inglês: <http://tools.ietf.org/html/rfc2705>. Acesso em 2 jul. 2010. ASTERISK, BRASIL. O que é o Asterisk? Disponível em: <http://www.asteriskbrasil.org/>. Acesso em: 20 set. 2010. ASTERISK. Asterisk Coding Guideline. Disponível em inglês: <http://www.asterisk.org/developers/coding-guidelines>. Acesso em 10 out 2010. BELLARD, Fabrice. QEMU, a Fast and Portable Dynamic Translator. Disponível em inglês: <http://www.usenix.org/publications/library/proceedings/usenix05/tech/freenix/full_pap ers/bellard/bellard.pdf>. Acesso em: 29 maio 2010. BOCHS. Welcome to the Bochs IA-32 Emulator Project. Disponível em inglês: <http://bochs.sourceforge.net/>. Acesso em: 25 maio 2010. CASSIMIRI, Alexandre. Virtualização: da teoria a soluções. Porto Alegre: Ufrgs, 2008. 207 p. Disponível em: <http://www.gta.ufrj.br/ensino/CPE758/artigos-basicos/cap4-v2.pdf>. Acesso em: 20 maio 2010. CALDAS, Anderson. Introdução a Linguagens de Programação. Alagoas: Universidade Federal de Alagoas, 2010. 18 slides. Disponível em: <http://www.lccv.ufal.br/downloads/cursos/curso-basico-de-c- 2010/arquivos/apresentacoes/Aula%2001.1%20- %20Introducao%20a%20Linguagem%20de%20Programacao%20C.pptx/>. Acesso em: 10 de jul. 2010. CARTER, Nicholas. Arquitetura de Computadores. Illinois, 2002. 236 p. CHANTRY, Darryl. Mapping applications to the cloud. Disponível em inglês: <http://msdn.microsoft.com/en-us/library/dd430340.aspx>. Acesso em: 28 abr. 2010. CREASY, R. J.. IBM Journal of Research and Development: The origin of the VM/370 time-sharing system. v. 25, n. 5, p. 483–490 Palo Alto, Ca, Usa: Ibm, 1981. Disponível em inglês: <http://pages.cs.wisc.edu/~stjones/proj/vm_reading/ibmrd2505M.pdf>. Acesso em: 25 abr. 2010. DAVENPORT, Malcolm. Asterisk as a Swiss Army Knife of Telephony. Disponível em inglês:
  • 65. 65 <https://wiki.asterisk.org/wiki/display/AST/Asterisk+as+a+Swiss+Army+Knife+of+Tel ephony>Acesso em: 20 set. 2010. DIKE, Jeff. The User-mode Linux Kernel Home Page. Disponível em inglês: < http://user-mode-linux.sourceforge.net/>. Acesso em: 25 abr. 2010. FIGUEIREDO, Luiz Henrique de; IERUSALIMSCHY, Roberto; CELES, Waldemar. A Linguagem Lua e suas aplicações em jogos. Disponível em: <http://www.lua.org/doc/wjogos04.pdf>. Acesso em: 09 abr. 2010. GARTNER. Special Report Virtualization. Disponível em inglês: <http://www.gartner.com/it/products/research/virtualization/virtualization.jsp?ref=3_28 _08LR>. Acesso em: 25 abr. 2010. GOLDEN, Bernard; SHEFFY, Clark. Virtualization for Dummies. Indianapolis: Wiley, 2008. 50 p. Disponível em inglês: <http://www.pcworld.com.vn/Handler/FileDowload.ashx?fileId=5150>. Acesso em: 02 maio 2010. GUY, Ed. IANA Registration for IAX. Disponível em inglês: <http://tools.ietf.org/html/draft-ietf-enum-iax-05>. Acesso em: 02 jul. 2010. IBM. Compiled versus Interpreted languages. Disponível em inglês: <http://publib.boulder.ibm.com/infocenter/zos/basics/topic/com.ibm.zos.zappldev/zappl dev_85.htm>. Acesso em 21 set. 2010. IBM. IBM Systems Virtualization. Version 2 Release 1. Disponível em inglês: <http://publib.boulder.ibm.com/infocenter/eserver/v1r2/topic/eicay/eicay.pdf>. Acesso em 20 mai. 2010. IBM; JONES, M. Tim. Virtual Linux. Disponível em inglês: <http://www.ibm.com/developerworks/library/l-linuxvirt/>. Acesso em: 02 jun. 2010. IETF. Session Initiation Protocol (sip). Disponível em inglês: <http://datatracker.ietf.org/wg/sip/charter/>. Acesso em 05 jul. 2010. INTEL. Virtualization. Disponível em inglês: <http://www.intel.com/technology/virtualization/>. Acesso em: 25 maio 2010. JONES, M. Tim. Virtual Linux. An overview of virtualization methods, architetures and implementations. Disponível em inglês: <http://www.ibm.com/developerworks/linux/library/l-linuxvirt/>. Acesso em: 29 abr. 2010. KVM. Kernel Based Virtual Machine. Disponível em inglês: <http://www.linux-kvm.org>. Acesso em: 31 maio 2010.
  • 66. 66 LOUDEN, C. Kenneth. Compiladores. Princípios e práticas. San Jose State University, 2004, 569 p. MANFRIN, Alexander. História: Conhecendo a origem da virtualização. Disponível em: <http://www.vmworld.com.br/br/index.php?option=com_content&view=article&id=80: historia-conhecendo-a-origem-da-virtualizacao&catid=50:virtualizacao>. Acesso em 20 maio 2010. MENASCÉ, Daniel A. Virtualization: Concepts, Applications, and performance modelling. Disponível em inglês: <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.61.6680&rep=rep1&type=p df>. Acesso em: 20 maio 2010. MICROSOFT. Hyper-V Server 2008 R2. Disponível em: <http://www.microsoft.com/brasil/servidores/hyper-v-server/default.mspx>. Acesso em: 31 maio 2010. ORIGUELA, Marcos. Paravirtualização com o Xen. Disponível em: <http://www.vivaolinux.com.br/artigo/Paravirtualizacao-com-o-Xen/>. Acesso em 29 maio 2010. PETTEY, Christy. Gartner Says Virtualization Will Be the Highest-Impact Trend in Infrastructure and Operations Market Through 2012. Disponível em inglês: <http://www.gartner.com/it/page.jsp?id=638207>. Acesso em: 25 abr. 2010. PROEBSTING, Todd A. Disruptive Programming Language Technologies: Microsoft Research. Disponível em inglês: <http://research.microsoft.com/en-us/um/people/toddpro/papers/disruptive.ppt>. Acesso em: 09 abr. 2010. QEMU. About. Disponível em inglês: <www.qemu.org>. Acesso em: 29 maio 2010. SEBESTA, Robert W. Conceitos de linguagem de programação. 5º Edição, 2002. 634 p. SHIELDS, Greg. The Shortcut Guide to Selecting the Right Virtualization Solution. San Francisco: Realtime Publishers, 2008. 72 p. Disponível em inglês: <http://nexus.realtimepublishers.com/sgsrvs.php>. Acesso em: 01 maio 2010. Stanford University. Interpreted Languages. Disponível em inglês: <http://pangea.stanford.edu/computerinfo/unix/programming/interpreted/>. Acesso em 10 ago. 2010. UBERHIP. Paravirtualization. Disponível em: <http://uberhip.com/godber/plug/Xen_Primer/assets/paravirtualization.png>. Acesso em: 02 maio 2010. VMWARE. Deploy the Most Advanced and Production-Proven Hypervisors. Disponível em inglês:
  • 67. 67 <http://www.vmware.com/products/esx/index.html>. Acesso em: 30 maio 2010. VMWARE. History of Virtualization. Disponível em inglês: <http://www.vmware.com/virtualization/history.html>. Acesso em: 02 abr. 2010. VMWARE, Understanding Full Virtualization, Paravirtualization, and Hardware Assist. Disponível em inglês: <http://www.vmware.com/files/pdf/VMware_paravirtualization.pdf>.Acesso em 03 abr. 2010. XEN. What is in Xen. Disponível em inglês: <http://www.xen.org/>. Acesso em: 01 jun. 2010. XEN. Xen Architecture Overview. Disponível em inglês: <http://wiki.xen.org/xenwiki/XenArchitecture?action=AttachFile&do=get&target=Xen +Architecture_Q1+2008.pdf>. Acesso em: 2 jun. 2010.
  • 68. 68 APÊNDICE A – CÓDIGO FONTE DA LINGUAGEM /* * dfn.c * * Programa criado para demonstracao de uso standalone da linguagem dfn */ #include <stdio.h> #include "dfn.h" #include "dfnlib.h" int main(int argc, char *argv[]) { if (argc < 2) { puts("Usage: dfn <filename.dfn>"); return 0; } dfn_execfile(argv[1]); return 0; } /* **DFN.h */ #ifndef dfn_h #define dfn_h typedef void (*dfn_CFunction) (void); typedef struct Object *dfn_Object; #define dfn_register(ref,func) (dfn_globalref(ref), dfn_pushcfunction(func)) void dfn_errorfunction(void (*fn) (char *s)); void dfn_error(char *s); int dfn_execfile(char *filename); int dfn_dostring(char *string); int dfn_call(char *functionname, int nparam); dfn_Object dfn_getparam(int number); float dfn_getnumber(dfn_Object object); char *dfn_getstring(dfn_Object object); char *dfn_copystring(dfn_Object object); dfn_CFunction dfn_getcfunction(dfn_Object object); void *dfn_getuserdata(dfn_Object object); dfn_Object dfn_getfield(dfn_Object object, char *field); dfn_Object dfn_getindexed(dfn_Object object, float index); dfn_Object dfn_getglobal(char *name); dfn_Object dfn_pop(void); int dfn_pushnil(void); int dfn_pushnumber(float n);
  • 69. 69 int dfn_pushstring(char *s); int dfn_pushcfunction(dfn_CFunction fn); int dfn_pushuserdata(void *u); int dfn_pushobject(dfn_Object object); int dfn_globalref(char *name); int dfn_storefield(dfn_Object object, char *field); int dfn_storeindexed(dfn_Object object, float index); int dfn_isnil(dfn_Object object); int dfn_isnumber(dfn_Object object); int dfn_isstring(dfn_Object object); int dfn_istable(dfn_Object object); int dfn_iscfunction(dfn_Object object); int dfn_isuserdata(dfn_Object object); #endif /* ** hash.c */ #include <string.h> #include <stdlib.h> #include "objects.h" #include "hash.h" #include "inout.h" #include "table.h" #include "dfn.h" // Pseudofuncs #define streq(s1,s2) (strcmp(s1,s2)==0) #define strneq(s1,s2) (strcmp(s1,s2)!=0) // Encapsulando as funcoes de alocacao de memoria do C #define new(s) ((s *)malloc(sizeof(s))) #define newvector(n,s) ((s *)calloc(n,sizeof(s))) #define nhash(t) ((t)->nhash) #define nodelist(t) ((t)->list) #define list(t,i) ((t)->list[i]) #define ref_tag(n) (tag(&(n)->ref)) #define ref_nvalue(n) (nvalue(&(n)->ref)) #define ref_svalue(n) (svalue(&(n)->ref)) static int head(Hash * t, Object * ref) { if (tag(ref) == T_NUMBER) return (((int) nvalue(ref)) % nhash(t)); else if (tag(ref) == T_STRING) { int h; char *name = svalue(ref); for (h = 0; *name != 0; name++) { /* name as bin */ h <<= 8; h += (unsigned char) *name; h %= nhash(t); } return h; } else {
  • 70. 70 dfn_reportbug("unexpected type to index table"); return -1; } } static Node *present(Hash * t, Object * ref, int h) { Node *n = NULL, *p; if (tag(ref) == T_NUMBER) { for (p = NULL, n = list(t, h); n != NULL; p = n, n = n- >next) if (ref_tag(n) == T_NUMBER && nvalue(ref) == ref_nvalue(n)) break; } else if (tag(ref) == T_STRING) { for (p = NULL, n = list(t, h); n != NULL; p = n, n = n- >next) if (ref_tag(n) == T_STRING && streq(svalue(ref), ref_svalue(n))) break; } if (n == NULL) return NULL; return n; } static void freelist(Node * n) { while (n) { Node *next = n->next; free(n); n = next; } } /* */ Hash *dfn_hashcreate(unsigned int nhash) { Hash *t = new(Hash); if (t == NULL) { dfn_error("not enough memory"); return NULL; } nhash(t) = nhash; markarray(t) = 0; nodelist(t) = newvector(nhash, Node *); if (nodelist(t) == NULL) { dfn_error("not enough memory"); return NULL; } return t; } /* */ void dfn_hashdelete(Hash * h) { int i; for (i = 0; i < nhash(h); i++)
  • 71. 71 freelist(list(h, i)); free(nodelist(h)); free(h); } /* */ Object *dfn_hashdefine(Hash * t, Object * ref) { int h; Node *n; h = head(t, ref); if (h < 0) return NULL; n = present(t, ref, h); if (n == NULL) { n = new(Node); if (n == NULL) { dfn_error("not enough memory"); return NULL; } n->ref = *ref; tag(&n->val) = T_NIL; n->next = list(t, h); list(t, h) = n; } return (&n->val); } /* */ void dfn_hashmark(Hash * h) { int i; markarray(h) = 1; for (i = 0; i < nhash(h); i++) { Node *n; for (n = list(h, i); n != NULL; n = n->next) { dfn_markobject(&n->ref); dfn_markobject(&n->val); } } } /* */ #include "dfn.h" static void firstnode(Hash * a, int h) { if (h < nhash(a)) { int i; for (i = h; i < nhash(a); i++) { if (list(a, i) != NULL && tag(&list(a, i)->val) != T_NIL) { dfn_pushobject(&list(a, i)->ref); dfn_pushobject(&list(a, i)->val); return;
  • 72. 72 } } } dfn_pushnil(); dfn_pushnil(); } void dfn_next(void) { Hash *a; Object *o = dfn_getparam(1); Object *r = dfn_getparam(2); if (o == NULL || r == NULL) { dfn_error("too few arguments to function `next'"); return; } if (dfn_getparam(3) != NULL) { dfn_error("too many arguments to function `next'"); return; } if (tag(o) != T_ARRAY) { dfn_error("first argument of function `next' is not a table"); return; } a = avalue(o); if (tag(r) == T_NIL) { firstnode(a, 0); return; } else { int h = head(a, r); if (h >= 0) { Node *n = list(a, h); while (n) { if (memcmp(&n->ref, r, sizeof(Object)) == 0) { if (n->next == NULL) { firstnode(a, h + 1); return; } else if (tag(&n->next->val) != T_NIL) { dfn_pushobject(&n->next- >ref); dfn_pushobject(&n->next- >val); return; } else { Node *next = n->next- >next; while (next != NULL && tag(&next->val) == T_NIL) next = next- >next; if (next == NULL) { firstnode(a, h + 1); return; } else { dfn_pushobject(&next->ref);
  • 73. 73 dfn_pushobject(&next->val); } return; } } n = n->next; } if (n == NULL) dfn_error("error in function 'next': reference not found"); } } } /* ** hash.h */ #ifndef hash_h #define hash_h typedef struct node { Object ref; Object val; struct node *next; } Node; typedef struct Hash { char mark; unsigned int nhash; Node **list; } Hash; #define markarray(t) ((t)->mark) Hash *dfn_hashcreate(unsigned int nhash); void dfn_hashdelete(Hash * h); Object *dfn_hashdefine(Hash * t, Object * ref); void dfn_hashmark(Hash * h); void dfn_next(void); #endif /* ** inout.c */ #include <stdio.h> #include <string.h> #include "objects.h" #include "hash.h" #include "inout.h" #include "table.h" /* Exported variables */
  • 74. 74 int dfn_linenumber; int dfn_debug; int dfn_debugline; /* Internal variables */ #ifndef MAXFUNCSTACK #define MAXFUNCSTACK 32 #endif static struct { int file; int function; } funcstack[MAXFUNCSTACK]; static int nfuncstack = 0; static FILE *fp; static char *st; static void (*usererror) (char *s); /* */ void dfn_errorfunction(void (*fn) (char *s)) { usererror = fn; } /* */ static int fileinput(void) { int c = fgetc(fp); int ntemp=c; return (c == EOF ? 0 : c); } /* */ static void fileunput(int c) { ungetc(c, fp); } /* */ static int stringinput(void) { st++; return (*(st - 1)); } /* */ static void stringunput(int c) { st--; } /* */ int dfn_openfile(char *fn) { dfn_linenumber = 1;
  • 75. 75 dfn_setinput(fileinput); dfn_setunput(fileunput); fp = fopen(fn, "r"); if (fp == NULL) return 1; if (dfn_addfile(fn)) return 1; return 0; } /* */ void dfn_closefile(void) { if (fp != NULL) { fclose(fp); fp = NULL; } } /* */ int dfn_openstring(char *s) { dfn_linenumber = 1; dfn_setinput(stringinput); dfn_setunput(stringunput); st = s; { char sn[64]; sprintf(sn, "String: %10.10s...", s); if (dfn_addfile(sn)) return 1; } return 0; } /* */ void dfn_error(char *s) { if (usererror != NULL) usererror(s); else fprintf(stderr, "dfn: %sn", s); } /* */ int dfn_pushfunction(int file, int function) { if (nfuncstack >= MAXFUNCSTACK - 1) { dfn_error("function stack overflow"); return 1; } funcstack[nfuncstack].file = file; funcstack[nfuncstack].function = function; nfuncstack++; return 0; }
  • 76. 76 /* */ void dfn_popfunction(void) { nfuncstack--; } /* */ void dfn_reportbug(char *s) { char msg[1024]; strcpy(msg, s); if (dfn_debugline != 0) { int i; if (nfuncstack > 0) { sprintf(strchr(msg, 0), "ntin statement begining at line %d in function "%s" of file "%s"", dfn_debugline, s_name(funcstack[nfuncstack - 1].function), dfn_file[funcstack[nfuncstack - 1].file]); sprintf(strchr(msg, 0), "ntactive stackn"); for (i = nfuncstack - 1; i >= 0; i--) sprintf(strchr(msg, 0), "t-> function "%s" of file "%s"n", s_name(funcstack[i].function), dfn_file[funcstack[i].file]); } else { sprintf(strchr(msg, 0), "ntin statement begining at line %d of file "%s"", dfn_debugline, dfn_filename()); } } dfn_error(msg); } /* ** inout.h */ #ifndef inout_h #define inout_h extern int dfn_linenumber; extern int dfn_debug; extern int dfn_debugline; int dfn_openfile(char *fn); void dfn_closefile(void); int dfn_openstring(char *s); int dfn_pushfunction(int file, int function); void dfn_popfunction(void); void dfn_reportbug(char *s); #endif
  • 77. 77 /* ** lex_yy.c */ # include "stdio.h" #define LEXDEBUG 1 # define U(x) x # define NLSTATE yyprevious=YYNEWLINE # define BEGIN yybgin = yysvec + 1 + # define INITIAL 0 # define YYLERR yysvec # define YYSTATE (yyestate-yysvec-1) # define YYOPTIM 1 # define YYLMAX BUFSIZ # define output(c) putc(c,yyout) # define input() (((yytchar=yysptr>yysbuf?U(*-- yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar) # define unput(c) {yytchar= (c);if(yytchar=='n')yylineno-- ;*yysptr++=yytchar;} # define yymore() (yymorfg=1) # define ECHO fprintf(yyout, "%s",yytext) # define REJECT { nstr = yyreject(); goto yyfussy;} int yyleng; extern char yytext[]; int yymorfg; extern char *yysptr, yysbuf[]; int yytchar; FILE *yyin = { NULL }, *yyout = { NULL}; extern int yylineno; struct yysvf { struct yywork *yystoff; struct yysvf *yyother; int *yystops; }; struct yysvf *yyestate; extern struct yysvf yysvec[], *yybgin; #include <stdlib.h> #include <string.h> #include "objects.h" #include "hash.h" #include "inout.h" #include "table.h" #include "y_tab.h" #undef input #undef unput static Input input; static Unput unput; void dfn_setinput(Input fn) { input = fn; } void dfn_setunput(Unput fn)
  • 78. 78 { unput = fn; } char *dfn_lasttext(void) { return yytext; } # define YYNEWLINE 10 yylex() { int nstr; extern int yyprevious; while ((nstr = yylook()) >= 0) yyfussy:switch (nstr) { case 0: if (yywrap()) return (0); break; case 1: ; break; case 2: { yylval.vInt = 1; return DEBUG; } break; case 3: { yylval.vInt = 0; return DEBUG; } break; case 4: dfn_linenumber++; break; case 5: ; break; case 6: return LOCAL; break; case 7: return IF; break; case 8: return THEN; break; case 9: return ELSE; break; case 10: return ELSEIF; break; case 11: return WHILE;
  • 79. 79 break; case 12: return DO; break; case 13: return REPEAT; break; case 14: return UNTIL; break; case 15: { yylval.vWord = dfn_nfile - 1; return FUNCTION; } break; case 16: return END; break; case 17: return RETURN; break; case 18: return LOCAL; break; case 19: return NIL; break; case 20: return AND; break; case 21: return OR; break; case 22: return NOT; break; case 23: return NE; break; case 24: return LE; break; case 25: return GE; break; case 26: return CONC; break; case 27: case 28: { yylval.vWord = dfn_findenclosedconstant(yytext); return STRING; } break; case 29: case 30: case 31: case 32:
  • 80. 80 { yylval.vFloat = atof(yytext); return NUMBER; } break; case 33: { yylval.vWord = dfn_findsymbol(yytext); return NAME; } break; case 34: return *yytext; break; case -1: break; default: fprintf(yyout, "bad switch yylook %d", nstr); } return (0); } /* end of yylex */ int yyvstop[] = { 0, 1, 0, 1, 0, 34, 0, 1, 34, 0, 4, 0, 34, 0, 34, 0, 34, 0, 34, 0, 29, 34, 0, 34, 0,
  • 85. 85 33, 0, 10, 33, 0, 33, 0, 13, 33, 0, 17, 33, 0, 2, 0, 33, 0, 15, 33, 0, 3, 0, 0 }; # define YYTYPE char struct yywork { YYTYPE verify, advance; } yycrank[] = { 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 1, 5, 6, 29, 4, 28, 0, 0, 0, 0, 0, 0, 0, 0, 7, 31, 0, 0, 6, 29, 6, 29, 0, 0, 0, 0, 0, 0, 0, 0, 7, 31, 7, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 4, 28, 0, 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 1, 3, 6, 30, 1, 8, 1, 9, 0, 0, 1, 10, 6, 29, 7, 31, 8, 33, 0, 0, 6, 29, 0, 0, 7, 32, 0, 0, 0, 0, 6, 29, 7, 31, 1, 11, 0, 0, 1, 12, 2, 27, 7, 31, 1, 13, 11, 39, 12, 40, 1, 13, 26, 56, 0, 0, 0, 0, 2, 8, 2, 9, 0, 0, 6, 29, 0, 0, 0, 0, 6, 29, 0, 0, 0, 0, 7, 31, 0, 0, 0, 0, 7, 31, 0, 0, 0, 0, 2, 11, 0, 0, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  • 86. 86 0, 0, 0, 0, 1, 14, 0, 0, 0, 0, 1, 15, 1, 16, 1, 17, 0, 0, 22, 52, 1, 18, 18, 47, 23, 53, 1, 19, 42, 63, 1, 20, 1, 21, 25, 55, 14, 42, 1, 22, 15, 43, 1, 23, 1, 24, 16, 44, 1, 25, 16, 45, 17, 46, 19, 48, 21, 51, 2, 14, 20, 49, 1, 26, 2, 15, 2, 16, 2, 17, 24, 54, 20, 50, 2, 18, 44, 64, 45, 65, 2, 19, 46, 66, 2, 20, 2, 21, 27, 57, 48, 67, 2, 22, 49, 68, 2, 23, 2, 24, 50, 69, 2, 25, 52, 70, 53, 72, 27, 58, 54, 73, 52, 71, 9, 34, 2, 26, 9, 35, 9, 35, 9, 35, 9, 35, 9, 35, 9, 35, 9, 35, 9, 35, 9, 35, 9, 35, 10, 36, 55, 74, 10, 37, 10, 37, 10, 37, 10, 37, 10, 37, 10, 37, 10, 37, 10, 37, 10, 37, 10, 37, 57, 75, 58, 76, 64, 80, 66, 81, 67, 82, 70, 83, 71, 84, 72, 85, 73, 86, 74, 87, 10, 38, 10, 38, 38, 61, 10, 38, 38, 61, 75, 88, 76, 89, 38, 62, 38, 62, 38, 62, 38, 62, 38, 62, 38, 62, 38, 62, 38, 62, 38, 62, 38, 62, 80, 92, 81, 93, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 82, 94, 83, 95, 84, 96, 10, 38, 10, 38, 86, 97, 10, 38, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 87, 98, 88, 99, 60, 79, 60, 79, 13, 41, 60, 79, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 13, 41, 33, 33, 89, 100, 60, 79, 60, 79, 92, 101, 60, 79, 93, 102, 95, 103, 33, 33, 33, 0, 96, 104, 99, 105, 100, 106, 102, 107, 106, 108, 107, 109, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 108, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 33, 0, 0, 0, 0, 35, 59, 35, 59, 33, 33, 35, 59, 0, 0, 0, 0, 33, 33, 0, 0, 0, 0, 0, 0, 0, 0, 33, 33, 0, 0, 0, 0, 0, 0, 0, 0, 36, 60, 36, 60, 36, 60, 36, 60, 36, 60, 36, 60, 36, 60,
  • 87. 87 36, 60, 36, 60, 36, 60, 0, 0, 0, 0, 33, 33, 0, 0, 0, 0, 33, 33, 35, 59, 35, 59, 0, 0, 35, 59, 36, 38, 36, 38, 59, 77, 36, 38, 59, 77, 0, 0, 0, 0, 59, 78, 59, 78, 59, 78, 59, 78, 59, 78, 59, 78, 59, 78, 59, 78, 59, 78, 59, 78, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 38, 36, 38, 0, 0, 36, 38, 77, 78, 77, 78, 77, 78, 77, 78, 77, 78, 77, 78, 77, 78, 77, 78, 77, 78, 77, 78, 79, 90, 0, 0, 79, 90, 0, 0, 0, 0, 79, 91, 79, 91, 79, 91, 79, 91, 79, 91, 79, 91, 79, 91, 79, 91, 79, 91, 79, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 90, 91, 0, 0}; struct yysvf yysvec[] = { 0, 0, 0, yycrank + -1, 0, yyvstop + 1, yycrank + -28, yysvec + 1, yyvstop + 3, yycrank + 0, 0, yyvstop + 5, yycrank + 4, 0, yyvstop + 7, yycrank + 0, 0, yyvstop + 10, yycrank + -11, 0, yyvstop + 12, yycrank + -17, 0, yyvstop + 14, yycrank + 7, 0, yyvstop + 16, yycrank + 107, 0, yyvstop + 18, yycrank + 119, 0, yyvstop + 20, yycrank + 6, 0, yyvstop + 23, yycrank + 7, 0, yyvstop + 25, yycrank + 158, 0, yyvstop + 27, yycrank + 4, yysvec + 13, yyvstop + 30, yycrank + 5, yysvec + 13, yyvstop + 33, yycrank + 11, yysvec + 13, yyvstop + 36, yycrank + 5, yysvec + 13, yyvstop + 39, yycrank + 5, yysvec + 13, yyvstop + 42, yycrank + 12, yysvec + 13, yyvstop + 45, yycrank + 21, yysvec + 13, yyvstop + 48, yycrank + 10, yysvec + 13, yyvstop + 51, yycrank + 4, yysvec + 13, yyvstop + 54, yycrank + 4, yysvec + 13, yyvstop + 57, yycrank + 21, yysvec + 13, yyvstop + 60, yycrank + 9, yysvec + 13, yyvstop + 63, yycrank + 9, 0, yyvstop + 66, yycrank + 40, 0, yyvstop + 68, yycrank + 0, yysvec + 4, yyvstop + 70, yycrank + 0, yysvec + 6, 0, yycrank + 0, 0, yyvstop + 72, yycrank + 0, yysvec + 7, 0, yycrank + 0, 0, yyvstop + 74, yycrank + -280, 0, yyvstop + 76, yycrank + 0, 0, yyvstop + 78, yycrank + 249, 0, yyvstop + 80, yycrank + 285, 0, yyvstop + 82, yycrank + 0, yysvec + 10, yyvstop + 84, yycrank + 146, 0, 0,
  • 88. 88 yycrank + 0, 0, yyvstop + 86, yycrank + 0, 0, yyvstop + 88, yycrank + 0, yysvec + 13, yyvstop + 90, yycrank + 10, yysvec + 13, yyvstop + 92, yycrank + 0, yysvec + 13, yyvstop + 94, yycrank + 19, yysvec + 13, yyvstop + 97, yycrank + 35, yysvec + 13, yyvstop + 99, yycrank + 27, yysvec + 13, yyvstop + 101, yycrank + 0, yysvec + 13, yyvstop + 103, yycrank + 42, yysvec + 13, yyvstop + 106, yycrank + 35, yysvec + 13, yyvstop + 108, yycrank + 30, yysvec + 13, yyvstop + 110, yycrank + 0, yysvec + 13, yyvstop + 112, yycrank + 36, yysvec + 13, yyvstop + 115, yycrank + 48, yysvec + 13, yyvstop + 117, yycrank + 35, yysvec + 13, yyvstop + 119, yycrank + 61, yysvec + 13, yyvstop + 121, yycrank + 0, 0, yyvstop + 123, yycrank + 76, 0, 0, yycrank + 67, 0, 0, yycrank + 312, 0, 0, yycrank + 183, yysvec + 36, yyvstop + 125, yycrank + 322, 0, 0, yycrank + 0, yysvec + 61, yyvstop + 128, yycrank + 0, yysvec + 13, yyvstop + 130, yycrank + 78, yysvec + 13, yyvstop + 133, yycrank + 0, yysvec + 13, yyvstop + 135, yycrank + 81, yysvec + 13, yyvstop + 138, yycrank + 84, yysvec + 13, yyvstop + 140, yycrank + 0, yysvec + 13, yyvstop + 142, yycrank + 0, yysvec + 13, yyvstop + 145, yycrank + 81, yysvec + 13, yyvstop + 148, yycrank + 66, yysvec + 13, yyvstop + 150, yycrank + 74, yysvec + 13, yyvstop + 152, yycrank + 80, yysvec + 13, yyvstop + 154, yycrank + 78, yysvec + 13, yyvstop + 156, yycrank + 94, 0, 0, yycrank + 93, 0, 0, yycrank + 341, 0, 0, yycrank + 0, yysvec + 77, yyvstop + 158, yycrank + 356, 0, 0, yycrank + 99, yysvec + 13, yyvstop + 160, yycrank + 89, yysvec + 13, yyvstop + 163, yycrank + 108, yysvec + 13, yyvstop + 165, yycrank + 120, yysvec + 13, yyvstop + 167, yycrank + 104, yysvec + 13, yyvstop + 169, yycrank + 0, yysvec + 13, yyvstop + 171, yycrank + 113, yysvec + 13, yyvstop + 174, yycrank + 148, yysvec + 13, yyvstop + 176, yycrank + 133, 0, 0, yycrank + 181, 0, 0, yycrank + 366, 0, 0, yycrank + 0, yysvec + 90, yyvstop + 178, yycrank + 183, yysvec + 13, yyvstop + 181, yycrank + 182, yysvec + 13, yyvstop + 183, yycrank + 0, yysvec + 13, yyvstop + 185, yycrank + 172, yysvec + 13, yyvstop + 189, yycrank + 181, yysvec + 13, yyvstop + 191, yycrank + 0, yysvec + 13, yyvstop + 193, yycrank + 0, yysvec + 13, yyvstop + 196, yycrank + 189, 0, 0,
  • 89. 89 yycrank + 195, 0, 0, yycrank + 0, yysvec + 13, yyvstop + 199, yycrank + 183, yysvec + 13, yyvstop + 202, yycrank + 0, yysvec + 13, yyvstop + 204, yycrank + 0, yysvec + 13, yyvstop + 207, yycrank + 0, 0, yyvstop + 210, yycrank + 178, 0, 0, yycrank + 186, yysvec + 13, yyvstop + 212, yycrank + 204, 0, 0, yycrank + 0, yysvec + 13, yyvstop + 214, yycrank + 0, 0, yyvstop + 217, 0, 0, 0 }; struct yywork *yytop = yycrank + 423; struct yysvf *yybgin = yysvec + 1; char yymatch[] = { 00, 01, 01, 01, 01, 01, 01, 01, 01, 011, 012, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 011, 01, '"', 01, 01, 01, 01, 047, 01, 01, 01, '+', 01, '+', 01, 01, '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 01, 01, 01, 01, 01, 01, 01, 'A', 'A', 'A', 'D', 'D', 'A', 'D', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 01, 01, 01, 01, 'A', 01, 'A', 'A', 'A', 'D', 'D', 'A', 'D', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 01, 01, 01, 01, 01, 0 }; char yyextra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #ifndef lint static char ncform_sccsid[] = "@(#)ncform 1.6 88/02/08 SMI"; /* from S5R2 1.2 */ #endif int yylineno = 1; # define YYU(x) x # define NLSTATE yyprevious=YYNEWLINE char yytext[YYLMAX]; struct yysvf *yylstate[YYLMAX], **yylsp, **yyolsp; char yysbuf[YYLMAX]; char *yysptr = yysbuf; int *yyfnd; extern struct yysvf *yyestate; int yyprevious = YYNEWLINE; yylook()
  • 90. 90 { // register struct yysvf *yystate, **lsp; struct yysvf *yystate, **lsp; // register struct yywork *yyt; struct yywork *yyt; struct yysvf *yyz; int yych, yyfirst; struct yywork *yyr; # ifdef LEXDEBUG int debug; # endif char *yylastch; /* start off machines */ # ifdef LEXDEBUG debug = 0; # endif yyfirst = 1; if (!yymorfg) yylastch = yytext; else { yymorfg = 0; yylastch = yytext + yyleng; } for (;;) { lsp = yylstate; yyestate = yystate = yybgin; if (yyprevious == YYNEWLINE) yystate++; for (;;) { yyt = yystate->yystoff; if (yyt == yycrank && !yyfirst) { /* may not be any transitions */ yyz = yystate->yyother; if (yyz == 0) break; if (yyz->yystoff == yycrank) break; } *yylastch++ = yych = input(); yyfirst = 0; tryagain: yyr = yyt; if ((int) yyt > (int) yycrank) { yyt = yyr + yych; if (yyt <= yytop && yyt->verify + yysvec == yystate) { if (yyt->advance + yysvec == YYLERR) { /* error transitions */ unput(*--yylastch); break; } *lsp++ = yystate = yyt->advance + yysvec; goto contin; } } # ifdef YYOPTIM else if ((int) yyt < (int) yycrank) { /* r < yycrank */
  • 91. 91 yyt = yyr = yycrank + (yycrank - yyt); # ifdef LEXDEBUG if (debug) fprintf(yyout, "compressed staten"); # endif yyt = yyt + yych; if (yyt <= yytop && yyt->verify + yysvec == yystate) { if (yyt->advance + yysvec == YYLERR) { /* error transitions */ unput(*--yylastch); break; } *lsp++ = yystate = yyt->advance + yysvec; goto contin; } yyt = yyr + YYU(yymatch[yych]); # ifdef LEXDEBUG if (debug) { fprintf(yyout, "try fall back character "); allprint(YYU(yymatch[yych])); putchar('n'); } # endif if (yyt <= yytop && yyt->verify + yysvec == yystate) { if (yyt->advance + yysvec == YYLERR) { /* error transition */ unput(*--yylastch); break; } *lsp++ = yystate = yyt->advance + yysvec; goto contin; } } if ((yystate = yystate->yyother) && (yyt = yystate->yystoff) != yycrank) { # ifdef LEXDEBUG if (debug) fprintf(yyout, "fall back to state %dn", yystate - yysvec - 1); # endif goto tryagain; } # endif else { unput(*--yylastch); break; } contin: # ifdef LEXDEBUG if (debug) { fprintf(yyout, "state %d char ", yystate - yysvec - 1); allprint(yych); putchar('n');
  • 92. 92 } # endif ; } # ifdef LEXDEBUG if (debug) { fprintf(yyout, "stopped at %d with ", *(lsp - 1) - yysvec - 1); allprint(yych); putchar('n'); } # endif while (lsp-- > yylstate) { *yylastch-- = 0; if (*lsp != 0 && (yyfnd = (*lsp)->yystops) && *yyfnd > 0) { yyolsp = lsp; if (yyextra[*yyfnd]) { /* must backup */ while (yyback((*lsp)->yystops, - *yyfnd) != 1 && lsp > yylstate) { lsp--; unput(*yylastch--); } } yyprevious = YYU(*yylastch); yylsp = lsp; yyleng = yylastch - yytext + 1; yytext[yyleng] = 0; # ifdef LEXDEBUG if (debug) { fprintf(yyout, "nmatch "); sprint(yytext); fprintf(yyout, " action %dn", *yyfnd); } # endif return (*yyfnd++); } unput(*yylastch); } if (yytext[0] == 0 /* && feof(yyin) */ ) { yysptr = yysbuf; return (0); } yyprevious = yytext[0] = input(); if (yyprevious > 0) output(yyprevious); yylastch = yytext; # ifdef LEXDEBUG if (debug) putchar('n'); # endif } } yyback(p, m) int *p; { if (p == 0) return (0); while (*p) {
  • 93. 93 if (*p++ == m) return (1); } return (0); } /* the following are only used in the lex library */ yyinput() { return (input()); } yyoutput(int c) { output(c); } yyunput(int c) { unput(c); } /* ** objects.c ** DRVS-All opcodes are here */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "objects.h" #include "hash.h" #include "inout.h" #include "table.h" #include "dfn.h" #define tonumber(o) ((tag(o) != T_NUMBER) && (dfn_tonumber(o) != 0)) #define tostring(o) ((tag(o) != T_STRING) && (dfn_tostring(o) != 0)) #ifndef MAXSTACK #define MAXSTACK 256 #endif static Object stack[MAXSTACK] = { {T_MARK, {NULL}} }; static Object *top = stack + 1, *base = stack + 1; /* */ static char *dfn_strconc(char *l, char *r) { char *s = calloc(strlen(l) + strlen(r) + 2, sizeof (char)); if (s == NULL) { dfn_error("not enough memory"); return NULL; } *s++ = 0;
  • 94. 94 return strcat(strcpy(s, l), r); } /* */ char *dfn_strdup(char *l) { char *s = calloc(strlen(l) + 2, sizeof (char)); if (s == NULL) { dfn_error("not enough memory"); return NULL; } *s++ = 0; /* create mark space */ return strcpy(s, l); } /* */ static int dfn_tonumber(Object * obj) { char *ptr; if (tag(obj) != T_STRING) { dfn_reportbug("unexpected type at conversion to number"); return 1; } nvalue(obj) = strtod(svalue(obj), &ptr); if (*ptr) { dfn_reportbug("string to number convertion failed"); return 2; } tag(obj) = T_NUMBER; return 0; } /* */ static Object *dfn_convtonumber(Object * obj) { static Object cvt; if (tag(obj) == T_NUMBER) { cvt = *obj; return &cvt; } tag(&cvt) = T_NIL; if (tag(obj) == T_STRING) { char *ptr; nvalue(&cvt) = strtod(svalue(obj), &ptr); if (*ptr == 0) tag(&cvt) = T_NUMBER; } return &cvt; } /* */ static int dfn_tostring(Object * obj) { static char s[256]; if (tag(obj) != T_NUMBER) { dfn_reportbug("unexpected type at conversion to string"); return 1; } if ((int) nvalue(obj) == nvalue(obj))
  • 95. 95 sprintf(s, "%d", (int) nvalue(obj)); else sprintf(s, "%g", nvalue(obj)); svalue(obj) = dfn_createstring(dfn_strdup(s)); if (svalue(obj) == NULL) return 1; tag(obj) = T_STRING; return 0; } /* */ int dfn_execute(Byte * pc) { while (1) { switch ((OpCode) * pc++) { case NOP: break; case PUSHNIL: tag(top++) = T_NIL; break; case PUSH0: tag(top) = T_NUMBER; nvalue(top++) = 0; break; case PUSH1: tag(top) = T_NUMBER; nvalue(top++) = 1; break; case PUSH2: tag(top) = T_NUMBER; nvalue(top++) = 2; break; case PUSHBYTE: tag(top) = T_NUMBER; nvalue(top++) = *pc++; break; case PUSHWORD: tag(top) = T_NUMBER; nvalue(top++) = *((Word *) (pc)); pc += sizeof (Word); break; case PUSHFLOAT: tag(top) = T_NUMBER; nvalue(top++) = *((float *) (pc)); pc += sizeof (float); break; case PUSHSTRING: { int w = *((Word *) (pc)); pc += sizeof (Word); tag(top) = T_STRING; svalue(top++) = dfn_constant[w]; } break; case PUSHLOCAL0:
  • 96. 96 *top++ = *(base + 0); break; case PUSHLOCAL1: *top++ = *(base + 1); break; case PUSHLOCAL2: *top++ = *(base + 2); break; case PUSHLOCAL3: *top++ = *(base + 3); break; case PUSHLOCAL4: *top++ = *(base + 4); break; case PUSHLOCAL5: *top++ = *(base + 5); break; case PUSHLOCAL6: *top++ = *(base + 6); break; case PUSHLOCAL7: *top++ = *(base + 7); break; case PUSHLOCAL8: *top++ = *(base + 8); break; case PUSHLOCAL9: *top++ = *(base + 9); break; case PUSHLOCAL: *top++ = *(base + (*pc++)); break; case PUSHGLOBAL: *top++ = s_object(*((Word *) (pc))); pc += sizeof (Word); break; case PUSHINDEXED: --top; if (tag(top - 1) != T_ARRAY) { dfn_reportbug("indexed expression not a table"); return 1; } { Object *h = dfn_hashdefine(avalue(top - 1), top); if (h == NULL) return 1; *(top - 1) = *h; } break; case PUSHMARK: tag(top++) = T_MARK; break; case PUSHOBJECT: *top = *(top - 3); top++; break;
  • 97. 97 case STORELOCAL0: *(base + 0) = *(--top); break; case STORELOCAL1: *(base + 1) = *(--top); break; case STORELOCAL2: *(base + 2) = *(--top); break; case STORELOCAL3: *(base + 3) = *(--top); break; case STORELOCAL4: *(base + 4) = *(--top); break; case STORELOCAL5: *(base + 5) = *(--top); break; case STORELOCAL6: *(base + 6) = *(--top); break; case STORELOCAL7: *(base + 7) = *(--top); break; case STORELOCAL8: *(base + 8) = *(--top); break; case STORELOCAL9: *(base + 9) = *(--top); break; case STORELOCAL: *(base + (*pc++)) = *(--top); break; case STOREGLOBAL: s_object(*((Word *) (pc))) = *(--top); pc += sizeof (Word); break; case STOREINDEXED0: if (tag(top - 3) != T_ARRAY) { dfn_reportbug("indexed expression not a table"); return 1; } { Object *h = dfn_hashdefine(avalue(top - 3), top - 2); if (h == NULL) return 1; *h = *(top - 1); } top -= 3; break; case STOREINDEXED: { int n = *pc++; if (tag(top - 3 - n) != T_ARRAY) { dfn_reportbug("indexed expression not a table"); return 1;
  • 98. 98 } { Object *h = dfn_hashdefine(avalue(top - 3 - n), top - 2 - n); if (h == NULL) return 1; *h = *(top - 1); } --top; } break; case STOREFIELD: if (tag(top - 3) != T_ARRAY) { dfn_error("internal error - table expected"); return 1; } *(dfn_hashdefine(avalue(top - 3), top - 2)) = *(top - 1); top -= 2; break; case ADJUST: { Object *newtop = base + *(pc++); if (top != newtop) { while (top < newtop) tag(top++) = T_NIL; top = newtop; } } break; case CREATEARRAY: if (tag(top - 1) == T_NIL) nvalue(top - 1) = 101; else { if (tonumber(top - 1)) return 1; if (nvalue(top - 1) <= 0) nvalue(top - 1) = 101; } avalue(top - 1) = dfn_createarray(dfn_hashcreate(nvalue(top - 1))); if (avalue(top - 1) == NULL) return 1; tag(top - 1) = T_ARRAY; break; case EQOP: { Object *l = top - 2; Object *r = top - 1; --top; if (tag(l) != tag(r)) tag(top - 1) = T_NIL; else { switch (tag(l)) { case T_NIL: tag(top - 1) = T_NUMBER; break;
  • 99. 99 case T_NUMBER: tag(top - 1) = (nvalue(l) == nvalue(r)) ? T_NUMBER : T_NIL; break; case T_ARRAY: tag(top - 1) = (avalue(l) == avalue(r)) ? T_NUMBER : T_NIL; break; case T_FUNCTION: tag(top - 1) = (bvalue(l) == bvalue(r)) ? T_NUMBER : T_NIL; break; case T_CFUNCTION: tag(top - 1) = (fvalue(l) == fvalue(r)) ? T_NUMBER : T_NIL; break; case T_USERDATA: tag(top - 1) = (uvalue(l) == uvalue(r)) ? T_NUMBER : T_NIL; break; case T_STRING: tag(top - 1) = (strcmp(svalue(l), svalue(r)) == 0) ? T_NUMBER : T_NIL; break; case T_MARK: return 1; } } nvalue(top - 1) = 1; } break; case LTOP: { Object *l = top - 2; Object *r = top - 1; --top; if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) tag(top - 1) = (nvalue(l) < nvalue(r)) ? T_NUMBER : T_NIL; else { if (tostring(l) || tostring(r)) return 1; tag(top - 1) = (strcmp(svalue(l), svalue(r)) < 0) ? T_NUMBER : T_NIL; } nvalue(top - 1) = 1; } break; case LEOP: { Object *l = top - 2; Object *r = top - 1; --top; if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) tag(top - 1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER : T_NIL; else { if (tostring(l) || tostring(r))
  • 100. 100 return 1; tag(top - 1) = (strcmp(svalue(l), svalue(r)) <= 0) ? T_NUMBER : T_NIL; } nvalue(top - 1) = 1; } break; case ADDOP: { Object *l = top - 2; Object *r = top - 1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) += nvalue(r); --top; } break; case SUBOP: { Object *l = top - 2; Object *r = top - 1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) -= nvalue(r); --top; } break; case MULTOP: { Object *l = top - 2; Object *r = top - 1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) *= nvalue(r); --top; } break; case DIVOP: { Object *l = top - 2; Object *r = top - 1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) /= nvalue(r); --top; } break; case CONCOP: { Object *l = top - 2; Object *r = top - 1; if (tostring(r) || tostring(l)) return 1; svalue(l) = dfn_createstring(dfn_strconc(svalue(l), svalue(r))); if (svalue(l) == NULL)
  • 101. 101 return 1; --top; } break; case MINUSOP: if (tonumber(top - 1)) return 1; nvalue(top - 1) = -nvalue(top - 1); break; case NOTOP: tag(top - 1) = tag(top - 1) == T_NIL ? T_NUMBER : T_NIL; break; case ONTJMP: { int n = *((Word *) (pc)); pc += sizeof (Word); if (tag(top - 1) != T_NIL) pc += n; } break; case ONFJMP: { int n = *((Word *) (pc)); pc += sizeof (Word); if (tag(top - 1) == T_NIL) pc += n; } break; case JMP: pc += *((Word *) (pc)) + sizeof (Word); break; case UPJMP: pc -= *((Word *) (pc)) - sizeof (Word); break; case IFFJMP: { int n = *((Word *) (pc)); pc += sizeof (Word); top--; if (tag(top) == T_NIL) pc += n; } break; case IFFUPJMP: { int n = *((Word *) (pc)); pc += sizeof (Word); top--; if (tag(top) == T_NIL) pc -= n; } break;
  • 102. 102 case POP: --top; break; case CALLFUNC: { Byte *newpc; Object *b = top - 1; while (tag(b) != T_MARK) b--; if (tag(b - 1) == T_FUNCTION) { dfn_debugline = 0; newpc = bvalue(b - 1); bvalue(b - 1) = pc; nvalue(b) = (base - stack); base = b + 1; pc = newpc; if (MAXSTACK - (base - stack) < STACKGAP) { dfn_error("stack overflow"); return 1; } } else if (tag(b - 1) == T_CFUNCTION) { int nparam; dfn_debugline = 0; nvalue(b) = (base - stack); base = b + 1; nparam = top - base; (fvalue(b - 1)) (); { int i; int nretval = top - base - nparam; top = base - 2; base = stack + (int) nvalue(base - 1); for (i = 0; i < nretval; i++) { *top = *(top + nparam + 2); ++top; } } } else { dfn_reportbug("call expression not a function"); return 1; } } break; case RETCODE: { int i; int shift = *pc++; int nretval = top - base - shift; top = base - 2; pc = bvalue(base - 2); base = stack + (int) nvalue(base - 1); for (i = 0; i < nretval; i++) { *top = *(top + shift + 2); ++top; } } break;
  • 103. 103 case HALT: return 0; case SETFUNCTION: { int file, func; file = *((Word *) (pc)); pc += sizeof (Word); func = *((Word *) (pc)); pc += sizeof (Word); if (dfn_pushfunction(file, func)) return 1; } break; case SETLINE: dfn_debugline = *((Word *) (pc)); pc += sizeof (Word); break; case RESET: dfn_popfunction(); break; default: dfn_error("internal error - opcode didn't match"); return 1; } } } /* */ void dfn_markstack(void) { Object *o; for (o = top - 1; o >= stack; o--) dfn_markobject(o); } /* */ int dfn_execfile(char *filename) { int x, y; y = dfn_openfile(filename); if (y) return 1; x=dfn_parse(); if( x ){ dfn_closefile(); return 1; } dfn_closefile(); return 0; } /* */ int dfn_dostring(char *string) { if (dfn_openstring(string))
  • 104. 104 return 1; if (dfn_parse()) return 1; return 0; } /* */ int dfn_call(char *functionname, int nparam) { static Byte startcode[] = {CALLFUNC, HALT}; int i; Object func = s_object(dfn_findsymbol(functionname)); if (tag(&func) != T_FUNCTION) return 1; for (i = 1; i <= nparam; i++) *(top - i + 2) = *(top - i); top += 2; tag(top - nparam - 1) = T_MARK; *(top - nparam - 2) = func; return (dfn_execute(startcode)); } /* */ Object *dfn_getparam(int number) { if (number <= 0 || number > top - base) return NULL; return (base + number - 1); } /* */ real dfn_getnumber(Object * object) { if (tonumber(object)) return 0.0; else return (nvalue(object)); } /* */ char *dfn_getstring(Object * object) { if (tostring(object)) return NULL; else return (svalue(object)); } /* */ char *dfn_copystring(Object * object) { if (tostring(object)) return NULL; else return (strdup(svalue(object))); } /* */ dfn_CFunction dfn_getcfunction(Object * object) { if (tag(object) != T_CFUNCTION)
  • 105. 105 return NULL; else return (fvalue(object)); } /* */ void *dfn_getuserdata(Object * object) { if (tag(object) != T_USERDATA) return NULL; else return (uvalue(object)); } /* */ Object *dfn_getfield(Object * object, char *field) { if (tag(object) != T_ARRAY) return NULL; else { Object ref; tag(&ref) = T_STRING; svalue(&ref) = dfn_createstring(dfn_strdup(field)); return (dfn_hashdefine(avalue(object), &ref)); } } /* */ Object *dfn_getindexed(Object * object, float index) { if (tag(object) != T_ARRAY) return NULL; else { Object ref; tag(&ref) = T_NUMBER; nvalue(&ref) = index; return (dfn_hashdefine(avalue(object), &ref)); } } /* */ Object *dfn_getglobal(char *name) { int n = dfn_findsymbol(name); if (n < 0) return NULL; return &s_object(n); } /* */ Object *dfn_pop(void) { if (top <= base) return NULL; top--; return top; } /* */ int dfn_pushnil(void) {
  • 106. 106 if ((top - stack) >= MAXSTACK - 1) { dfn_error("stack overflow"); return 1; } tag(top) = T_NIL; return 0; } /* */ int dfn_pushnumber(real n) { if ((top - stack) >= MAXSTACK - 1) { dfn_error("stack overflow"); return 1; } tag(top) = T_NUMBER; nvalue(top++) = n; return 0; } /* */ int dfn_pushstring(char *s) { if ((top - stack) >= MAXSTACK - 1) { dfn_error("stack overflow"); return 1; } tag(top) = T_STRING; svalue(top++) = dfn_createstring(dfn_strdup(s)); return 0; } /* */ int dfn_pushcfunction(dfn_CFunction fn) { if ((top - stack) >= MAXSTACK - 1) { dfn_error("stack overflow"); return 1; } tag(top) = T_CFUNCTION; fvalue(top++) = fn; return 0; } /* */ int dfn_pushuserdata(void *u) { if ((top - stack) >= MAXSTACK - 1) { dfn_error("stack overflow"); return 1; } tag(top) = T_USERDATA; uvalue(top++) = u; return 0; } /* */ int dfn_pushobject(Object * o) { if ((top - stack) >= MAXSTACK - 1) { dfn_error("stack overflow");
  • 107. 107 return 1; } *top++ = *o; return 0; } /* */ int dfn_globalref(char *name) { int n = dfn_findsymbol(name); if (n < 0) return 1; if (tag(top - 1) == T_MARK) return 1; s_object(n) = *(--top); return 0; } /* */ int dfn_storefield(dfn_Object object, char *field) { if (tag(object) != T_ARRAY) return 1; else { Object ref, *h; tag(&ref) = T_STRING; svalue(&ref) = dfn_createstring(dfn_strdup(field)); h = dfn_hashdefine(avalue(object), &ref); if (h == NULL) return 1; if (tag(top - 1) == T_MARK) return 1; *h = *(--top); } return 0; } /* */ int dfn_storeindexed(dfn_Object object, float index) { if (tag(object) != T_ARRAY) return 1; else { Object ref, *h; tag(&ref) = T_NUMBER; nvalue(&ref) = index; h = dfn_hashdefine(avalue(object), &ref); if (h == NULL) return 1; if (tag(top - 1) == T_MARK) return 1; *h = *(--top); } return 0; } /* */ int dfn_isnil(Object * object) { return (object != NULL && tag(object) == T_NIL); }
  • 108. 108 /* */ int dfn_isnumber(Object * object) { return (object != NULL && tag(object) == T_NUMBER); } /* */ int dfn_isstring(Object * object) { return (object != NULL && tag(object) == T_STRING); } /* */ int dfn_istable(Object * object) { return (object != NULL && tag(object) == T_ARRAY); } /* */ int dfn_iscfunction(Object * object) { return (object != NULL && tag(object) == T_CFUNCTION); } /* */ int dfn_isuserdata(Object * object) { return (object != NULL && tag(object) == T_USERDATA); } /* */ void dfn_type(void) { Object *o = dfn_getparam(1); dfn_pushstring(dfn_constant[tag(o)]); } /* */ void dfn_obj2number(void) { Object *o = dfn_getparam(1); dfn_pushobject(dfn_convtonumber(o)); } /* */ void dfn_print(void) { int i = 1; void *obj; while ((obj = dfn_getparam(i++)) != NULL) { if (dfn_isnumber(obj)) printf("%gn", dfn_getnumber(obj)); else if (dfn_isstring(obj)) printf("%sn", dfn_getstring(obj)); else if (dfn_iscfunction(obj)) printf("function: %pn", dfn_getcfunction(obj)); else if (dfn_isuserdata(obj)) printf("usertype: %pn", dfn_getuserdata(obj)); else if (dfn_istable(obj)) printf("table: %pn", obj);
  • 109. 109 else if (dfn_isnil(obj)) printf("nulln"); else printf("print: invalid parametern"); } } /* ** objects.h */ #ifndef objects_h #define objects_h #ifndef STACKGAP #define STACKGAP 128 #endif #ifndef real #define real float #endif typedef unsigned char Byte; typedef unsigned short Word; typedef enum { NOP, PUSHNIL, PUSH0, PUSH1, PUSH2, PUSHBYTE, PUSHWORD, PUSHFLOAT, PUSHSTRING, PUSHLOCAL0, PUSHLOCAL1, PUSHLOCAL2, PUSHLOCAL3, PUSHLOCAL4, PUSHLOCAL5, PUSHLOCAL6, PUSHLOCAL7, PUSHLOCAL8, PUSHLOCAL9, PUSHLOCAL, PUSHGLOBAL, PUSHINDEXED, PUSHMARK, PUSHOBJECT, STORELOCAL0, STORELOCAL1, STORELOCAL2, STORELOCAL3, STORELOCAL4, STORELOCAL5, STORELOCAL6, STORELOCAL7, STORELOCAL8, STORELOCAL9, STORELOCAL, STOREGLOBAL, STOREINDEXED0, STOREINDEXED, STOREFIELD, ADJUST, CREATEARRAY, EQOP, LTOP, LEOP, ADDOP, SUBOP, MULTOP, DIVOP, CONCOP,
  • 110. 110 MINUSOP, NOTOP, ONTJMP, ONFJMP, JMP, UPJMP, IFFJMP, IFFUPJMP, POP, CALLFUNC, RETCODE, HALT, SETFUNCTION, SETLINE, RESET } OpCode; typedef enum { T_MARK, T_NIL, T_NUMBER, T_STRING, T_ARRAY, T_FUNCTION, T_CFUNCTION, T_USERDATA } Type; typedef void (*Cfunction) (void); typedef int (*Input) (void); typedef void (*Unput) (int); typedef union { Cfunction f; real n; char *s; Byte *b; struct Hash *a; void *u; } Value; typedef struct Object { Type tag; Value value; } Object; typedef struct { char *name; Object object; } Symbol; /* Macros to access structure members */ #define tag(o) ((o)->tag) #define nvalue(o) ((o)->value.n) #define svalue(o) ((o)->value.s) #define bvalue(o) ((o)->value.b) #define avalue(o) ((o)->value.a) #define fvalue(o) ((o)->value.f) #define uvalue(o) ((o)->value.u) /* Macros to access symbol table */
  • 111. 111 #define s_name(i) (dfn_table[i].name) #define s_object(i) (dfn_table[i].object) #define s_tag(i) (tag(&s_object(i))) #define s_nvalue(i) (nvalue(&s_object(i))) #define s_svalue(i) (svalue(&s_object(i))) #define s_bvalue(i) (bvalue(&s_object(i))) #define s_avalue(i) (avalue(&s_object(i))) #define s_fvalue(i) (fvalue(&s_object(i))) #define s_uvalue(i) (uvalue(&s_object(i))) /* Exported functions */ int dfn_execute(Byte * pc); void dfn_markstack(void); char *dfn_strdup(char *l); void dfn_setinput(Input fn); /* from "dfn.lex" module */ void dfn_setunput(Unput fn); /* from "dfn.lex" module */ char *dfn_lasttext(void); /* from "dfn.lex" module */ int dfn_parse(void); /* from "dfn.stx" module */ void dfn_type(void); void dfn_obj2number(void); void dfn_print(void); #endif /* ** table.c */ #include <stdlib.h> #include <string.h> #include "objects.h" #include "hash.h" #include "inout.h" #include "table.h" #include "dfn.h" #define streq(s1,s2) (strcmp(s1,s2)==0) #ifndef MAXSYMBOL #define MAXSYMBOL 512 #endif static Symbol tablebuffer[MAXSYMBOL] = { {"type", {T_CFUNCTION, {dfn_type}}}, {"strtonum", {T_CFUNCTION, {dfn_obj2number}}}, {"next", {T_CFUNCTION, {dfn_next}}}, {"nextvar", {T_CFUNCTION, {dfn_nextvar}}}, {"print", {T_CFUNCTION, {dfn_print}}} }; Symbol *dfn_table = tablebuffer; Word dfn_ntable = 5; #ifndef MAXCONSTANT #define MAXCONSTANT 256 #endif static char *constantbuffer[MAXCONSTANT] = { "mark", "nil", "number",
  • 112. 112 "string", "table", "function", "cfunction" }; char **dfn_constant = constantbuffer; Word dfn_nconstant = T_CFUNCTION + 1; #ifndef MAXSTRING #define MAXSTRING 512 #endif static char *stringbuffer[MAXSTRING]; char **dfn_string = stringbuffer; Word dfn_nstring = 0; #ifndef MAXARRAY #define MAXARRAY 512 #endif static Hash *arraybuffer[MAXARRAY]; Hash **dfn_array = arraybuffer; Word dfn_narray = 0; #define MAXFILE 20 char *dfn_file[MAXFILE]; int dfn_nfile; /* */ int dfn_findsymbol(char *s) { int i; for (i = 0; i < dfn_ntable; i++) if (streq(s, s_name(i))) return i; if (dfn_ntable >= MAXSYMBOL - 1) { dfn_error("symbol table overflow"); return -1; } s_name(dfn_ntable) = strdup(s); if (s_name(dfn_ntable) == NULL) { dfn_error("not enough memory"); return -1; } s_tag(dfn_ntable++) = T_NIL; return (dfn_ntable - 1); } /* ** */ int dfn_findenclosedconstant(char *s) { int i, j, l = strlen(s); char *c = calloc(l, sizeof(char)); c++; /* scape characters */ for (i = 1, j = 0; i < l - 1; i++) { if (s[i] == '') {
  • 113. 113 switch (s[++i]) { case 'n': c[j++] = 'n'; break; case 't': c[j++] = 't'; break; case 'r': c[j++] = 'r'; break; default: c[j++] = ''; c[j++] = c[i]; break; } } else c[j++] = s[i]; } c[j++] = 0; for (i = 0; i < dfn_nconstant; i++) if (streq(c, dfn_constant[i])) { free(c - 1); return i; } if (dfn_nconstant >= MAXCONSTANT - 1) { dfn_error("dfn: constant string table overflow"); return -1; } dfn_constant[dfn_nconstant++] = c; return (dfn_nconstant - 1); } /* */ int dfn_findconstant(char *s) { int i; for (i = 0; i < dfn_nconstant; i++) if (streq(s, dfn_constant[i])) return i; if (dfn_nconstant >= MAXCONSTANT - 1) { dfn_error("dfn: constant string table overflow"); return -1; } { char *c = calloc(strlen(s) + 2, sizeof(char)); c++; dfn_constant[dfn_nconstant++] = strcpy(c, s); } return (dfn_nconstant - 1); } /* */ void dfn_markobject(Object * o) { if (tag(o) == T_STRING) dfn_markstring(svalue(o)) = 1; else if (tag(o) == T_ARRAY && markarray(avalue(o)) == 0)
  • 114. 114 dfn_hashmark(avalue(o)); } /* */ static void dfn_marktable(void) { int i; for (i = 0; i < dfn_ntable; i++) dfn_markobject(&s_object(i)); } /* */ static void dfn_pack(void) { dfn_markstack(); dfn_marktable(); { int i, j; for (i = j = 0; i < dfn_nstring; i++) if (dfn_markstring(dfn_string[i]) == 1) { dfn_string[j++] = dfn_string[i]; dfn_markstring(dfn_string[i]) = 0; } else { free(dfn_string[i] - 1); } dfn_nstring = j; } { int i, j; for (i = j = 0; i < dfn_narray; i++) if (markarray(dfn_array[i]) == 1) { dfn_array[j++] = dfn_array[i]; markarray(dfn_array[i]) = 0; } else { dfn_hashdelete(dfn_array[i]); } dfn_narray = j; } } /* */ char *dfn_createstring(char *s) { if (s == NULL) return NULL; if (dfn_nstring >= MAXSTRING - 1) { dfn_pack(); if (dfn_nstring >= MAXSTRING - 1) { dfn_error("string table overflow"); return NULL; } } dfn_string[dfn_nstring++] = s; return s; }
  • 115. 115 /* */ void *dfn_createarray(void *a) { if (a == NULL) return NULL; if (dfn_narray >= MAXARRAY - 1) { dfn_pack(); if (dfn_narray >= MAXARRAY - 1) { dfn_error("indexed table overflow"); return NULL; } } dfn_array[dfn_narray++] = a; return a; } /* */ int dfn_addfile(char *fn) { if (dfn_nfile >= MAXFILE - 1) { dfn_error("too many files"); return 1; } if ((dfn_file[dfn_nfile++] = strdup(fn)) == NULL) { dfn_error("not enough memory"); return 1; } return 0; } /* */ char *dfn_filename(void) { return dfn_file[dfn_nfile - 1]; } /* */ void dfn_nextvar(void) { int index; Object *o = dfn_getparam(1); if (o == NULL) { dfn_error("too few arguments to function `nextvar'"); return; } if (dfn_getparam(2) != NULL) { dfn_error("too many arguments to function `nextvar'"); return; } if (tag(o) == T_NIL) { index = 0; } else if (tag(o) != T_STRING) { dfn_error("incorrect argument to function `nextvar'"); return;
  • 116. 116 } else { for (index = 0; index < dfn_ntable; index++) if (streq(s_name(index), svalue(o))) break; if (index == dfn_ntable) { dfn_error("name not found in function `nextvar'"); return; } index++; while (index < dfn_ntable - 1 && tag(&s_object(index)) == T_NIL) index++; if (index == dfn_ntable - 1) { dfn_pushnil(); dfn_pushnil(); return; } } { Object name; tag(&name) = T_STRING; svalue(&name) = dfn_createstring(dfn_strdup(s_name(index))); if (dfn_pushobject(&name)) return; if (dfn_pushobject(&s_object(index))) return; } } /* ** table.c */ #ifndef table_h #define table_h extern Symbol *dfn_table; extern Word dfn_ntable; extern char **dfn_constant; extern Word dfn_nconstant; extern char **dfn_string; extern Word dfn_nstring; extern Hash **dfn_array; extern Word dfn_narray; extern char *dfn_file[]; extern int dfn_nfile; #define dfn_markstring(s) (*((s)-1)) int dfn_findsymbol(char *s);
  • 117. 117 int dfn_findenclosedconstant(char *s); int dfn_findconstant(char *s); void dfn_markobject(Object * o); char *dfn_createstring(char *s); void *dfn_createarray(void *a); int dfn_addfile(char *fn); char *dfn_filename(void); void dfn_nextvar(void); #endif /* * y_tab.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "objects.h" #include "hash.h" #include "inout.h" #include "table.h" #include "dfn.h" #ifndef ALIGNMENT #define ALIGNMENT (sizeof(void *)) #endif #ifndef MAXCODE #define MAXCODE 1024 #endif static long buffer[MAXCODE]; static Byte *code = (Byte *) buffer; static long mainbuffer[MAXCODE]; static Byte *maincode = (Byte *) mainbuffer; static Byte *basepc; static Byte *pc; #define MAXVAR 32 static long varbuffer[MAXVAR]; static Byte nvarbuffer = 0; /* number of variables at a list */ static Word localvar[STACKGAP]; static Byte nlocalvar = 0; /* number of local variables */ static int ntemp; /* number of temporary var into stack */ static int err; /* flag to indicate error */ /* Internal functions */ #define align(n) align_n(sizeof(n)) static void code_byte(Byte c) { if (pc - basepc > MAXCODE - 1) { dfn_error("code buffer overflow"); err = 1;
  • 118. 118 } *pc++ = c; } static void code_word(Word n) { if (pc - basepc > MAXCODE - sizeof(Word)) { dfn_error("code buffer overflow"); err = 1; } *((Word *) pc) = n; pc += sizeof(Word); } static void code_float(float n) { if (pc - basepc > MAXCODE - sizeof(float)) { dfn_error("code buffer overflow"); err = 1; } *((float *) pc) = n; pc += sizeof(float); } static void incr_ntemp(void) { if (ntemp + nlocalvar + MAXVAR + 1 < STACKGAP) ntemp++; else { dfn_error("stack overflow"); err = 1; } } static void incr_nlocalvar(void) { if (ntemp + nlocalvar + MAXVAR + 1 < STACKGAP) nlocalvar++; else { dfn_error("too many local variables or expression too complicate"); err = 1; } } static void incr_nvarbuffer(void) { if (nvarbuffer < MAXVAR - 1) nvarbuffer++; else { dfn_error("variable buffer overflow"); err = 1; } } static void align_n(unsigned size) { if (size > ALIGNMENT) size = ALIGNMENT; while (((pc + 1 - code) % size) != 0) /* +1 to include BYTECODE */
  • 119. 119 code_byte(NOP); } static void code_number(float f) { int i = f; if (f == i) { /* f has an integer value */ if (i <= 2) code_byte(PUSH0 + i); else if (i <= 255) { code_byte(PUSHBYTE); code_byte(i); } else { align(Word); code_byte(PUSHWORD); code_word(i); } } else { align(float); code_byte(PUSHFLOAT); code_float(f); } incr_ntemp(); } typedef union { int vInt; long vLong; float vFloat; Word vWord; Byte *pByte; } YYSTYPE; #define NIL 257 #define IF 258 #define THEN 259 #define ELSE 260 #define ELSEIF 261 #define WHILE 262 #define DO 263 #define REPEAT 264 #define UNTIL 265 #define END 266 #define RETURN 267 #define LOCAL 268 #define NUMBER 269 #define FUNCTION 270 #define NAME 271 #define STRING 272 #define DEBUG 273 #define NOT 274 #define AND 275 #define OR 276 #define NE 277 #define LE 278 #define GE 279 #define CONC 280 #define UNARY 281 #define ENDWHILE 300 #define ENDIF 301
  • 120. 120 #define yyclearin yychar = -1 #define yyerrok yyerrflag = 0 extern int yychar; extern int yyerrflag; #ifndef YYMAXDEPTH #define YYMAXDEPTH 150 #endif YYSTYPE yylval, yyval; # define YYERRCODE 256 /* ** Search a local name and if find return its index. If do not find return -1 */ static int dfn_localname(Word n) { int i; for (i = nlocalvar - 1; i >= 0; i--) if (n == localvar[i]) return i; /* local var */ return -1; /* global var */ } /* ** Push a variable given a number. If number is positive, push global variable ** indexed by (number -1). If negative, push local indexed by ABS(number)-1. ** Otherwise, if zero, push indexed variable (record). */ static void dfn_pushvar(long number) { if (number > 0) { /* global var */ align(Word); code_byte(PUSHGLOBAL); code_word(number - 1); incr_ntemp(); } else if (number < 0) { /* local var */ number = (-number) - 1; if (number < 10) code_byte(PUSHLOCAL0 + number); else { code_byte(PUSHLOCAL); code_byte(number); } incr_ntemp(); } else { code_byte(PUSHINDEXED); ntemp--; } } static void dfn_codeadjust(int n) { code_byte(ADJUST);
  • 121. 121 code_byte(n + nlocalvar); } static void dfn_codestore(int i) { if (varbuffer[i] > 0) { /* global var */ align(Word); code_byte(STOREGLOBAL); code_word(varbuffer[i] - 1); } else if (varbuffer[i] < 0) { /* local var */ int number = (-varbuffer[i]) - 1; if (number < 10) code_byte(STORELOCAL0 + number); else { code_byte(STORELOCAL); code_byte(number); } } else { /* indexed var */ int j; int upper = 0; /* number of indexed variables upper */ int param; /* number of itens until indexed expression */ for (j = i + 1; j < nvarbuffer; j++) if (varbuffer[j] == 0) upper++; param = upper * 2 + i; if (param == 0) code_byte(STOREINDEXED0); else { code_byte(STOREINDEXED); code_byte(param); } } } void yyerror(char *s) { static char msg[256]; sprintf(msg, "%s near "%s" at line %d in file "%s"", s, dfn_lasttext(), dfn_linenumber, dfn_filename()); dfn_error(msg); err = 1; } int yywrap(void) { return 1; } /* ** Parse DFN Languace code and execute global statement. ** Return 0 on success or 1 on error. */ int dfn_parse(void) { Byte *initcode = maincode; err = 0;
  • 122. 122 if (yyparse() || (err == 1)) return 1; *maincode++ = HALT; if (dfn_execute(initcode)) return 1; maincode = initcode; return 0; } int yyexca[] = { -1, 1, 0, -1, -2, 2, -1, 19, 40, 65, 91, 95, 46, 97, -2, 92, -1, 29, 40, 65, 91, 95, 46, 97, -2, 51, -1, 70, 275, 33, 276, 33, 61, 33, 277, 33, 62, 33, 60, 33, 278, 33, 279, 33, 280, 33, 43, 33, 45, 33, 42, 33, 47, 33, -2, 68, -1, 71, 91, 95, 46, 97, -2, 93, -1, 102, 260, 27, 261, 27, 265, 27, 266, 27, 267, 27, -2, 11, -1, 117, 93, 85, -2, 87, -1, 122, 267, 30,
  • 123. 123 -2, 29, -1, 145, 275, 33, 276, 33, 61, 33, 277, 33, 62, 33, 60, 33, 278, 33, 279, 33, 280, 33, 43, 33, 45, 33, 42, 33, 47, 33, -2, 70, }; # define YYNPROD 105 # define YYLAST 318 int yyact[] = { 54, 52, 136, 53, 13, 55, 54, 52, 14, 53, 15, 55, 5, 166, 18, 6, 129, 21, 47, 46, 48, 107, 104, 97, 47, 46, 48, 54, 52, 80, 53, 21, 55, 54, 52, 40, 53, 9, 55, 54, 52, 158, 53, 160, 55, 47, 46, 48, 159, 101, 81, 47, 46, 48, 10, 54, 52, 126, 53, 67, 55, 54, 52, 60, 53, 155, 55, 148, 149, 135, 147, 108, 150, 47, 46, 48, 73, 23, 75, 47, 46, 48, 7, 25, 38, 153, 26, 164, 27, 117, 61, 62, 74, 11, 76, 54, 24, 127, 65, 66, 55, 37, 154, 151, 103, 111, 72, 28, 93, 94, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 116, 59, 77, 54, 52, 118, 53, 99, 55, 110, 95, 64, 44, 70, 109, 29, 33, 105, 106, 42, 112, 41, 165, 139, 19, 17, 152, 79, 123, 43, 119, 20, 114, 113, 98, 63, 144, 143, 122, 68, 39, 36, 130, 35, 120, 12, 8, 102, 125, 128, 141, 78, 69, 70, 71, 142, 131, 132, 140, 22, 124, 4, 3, 2, 121, 96, 138, 146, 137, 134, 157, 133, 115, 16, 1, 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, 161, 0, 0, 0, 0, 162, 0, 0, 0, 168, 0, 172, 145, 163, 171, 0, 174, 0, 0, 0, 169, 156, 167, 170, 173, 57, 58, 49, 50, 51, 56, 57, 58, 49, 50, 51, 56, 175, 0, 0, 100, 0, 45, 0, 0, 0, 0, 70, 0, 0, 0, 0, 57, 58, 49, 50, 51, 56, 57, 58, 49, 50, 51, 56, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 58, 49, 50, 51, 56, 0, 0, 49, 50, 51, 56, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 21, 31, 0, 34 }; int yypact[] = { -1000, -258, -1000, -1000, -1000, -234, -1000, 34, -254, -1000, -1000, -1000, -1000, 43, -1000, -1000, 40, -1000, -236, -1000, -1000, -1000, 93, -9, -1000, 43, 43, 43, 92, -1000,
  • 124. 124 -1000, -1000, -1000, -1000, 43, 43, -1000, 43, -240, 62, 31, -13, 48, 83, -242, -1000, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, -1000, -1000, 90, 13, -1000, -1000, -248, 43, 19, -15, -216, -1000, 60, -1000, -1000, -249, -1000, -1000, 43, -250, 43, 89, 61, -1000, -1000, -3, -3, -3, -3, -3, -3, 53, 53, -1000, -1000, 82, -1000, -1000, -1000, -2, -1000, 85, 13, -1000, 43, -1000, -1000, 31, 43, -36, -1000, 56, 60, -1000, -255, -1000, 43, 43, -1000, -269, -1000, -1000, -1000, 13, 34, -1000, 43, -1000, 13, -1000, -1000, -1000, -1000, -193, 19, 19, -53, 59, -1000, -1000, -8, 58, 43, -1000, -1000, -1000, -1000, -226, -1000, -218, -223, -1000, 43, -1000, -269, 26, -1000, -1000, -1000, 13, -253, 43, -1000, -1000, -1000, -42, -1000, 43, 43, -1000, 34, -1000, 13, -1000, -1000, -1000, -1000, -193, -1000 }; int yypgo[] = { 0, 195, 50, 96, 71, 135, 194, 193, 192, 190, 189, 187, 136, 186, 184, 82, 54, 183, 182, 180, 172, 170, 59, 168, 167, 166, 63, 70, 164, 162, 137, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 150, 149, 148, 69, 147, 144, 65, 143, 142, 140, 76, 138 }; int yyr1[] = { 0, 1, 14, 1, 1, 1, 19, 21, 17, 23, 23, 24, 15, 16, 16, 25, 28, 25, 29, 25, 25, 25, 25, 27, 27, 27, 32, 33, 22, 34, 35, 34, 2, 26, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 36, 3, 3, 3, 3, 3, 3, 3, 3, 38, 3, 39, 3, 37, 37, 41, 30, 40, 4, 4, 5, 42, 5, 20, 20, 43, 43, 13, 13, 7, 7, 8, 8, 9, 9, 45, 44, 10, 10, 46, 11, 48, 11, 47, 6, 6, 12, 49, 12, 50, 12, 31, 31, 51, 52, 51, 18 }; int yyr2[] = { 0, 0, 1, 9, 4, 4, 1, 1, 19, 0, 6, 1, 4, 0, 2, 17, 1, 17, 1, 13, 7, 3, 4, 0, 4, 15, 1, 1, 9, 0, 1, 9, 1, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 1, 9, 9, 3, 3, 3, 3, 3, 5, 1, 11, 1, 11, 1, 2, 1, 11, 3, 1, 3, 3, 1, 9, 0, 2, 3, 7, 1, 3, 7, 7, 1, 3, 3, 7, 1, 9, 1, 3, 1, 5, 1, 9, 3, 3, 7, 3, 1, 11, 1, 9, 5, 9, 1, 1, 6, 3 }; int yychk[] = { -1000, -1, -14, -17, -18, 270, 273, -15, -24, 271, -16, 59, -25, 258, 262, 264, -6, -30, 268, -12,
  • 125. 125 -40, 271, -19, -26, -3, 40, 43, 45, 64, -12, 269, 272, 257, -30, 274, -28, -29, 61, 44, -31, 271, -49, -50, -41, 40, 259, 61, 60, 62, 277, 278, 279, 43, 45, 42, 47, 280, 275, 276, -3, -26, -26, -26, -36, 40, -26, -26, -22, -32, -5, -3, -12, 44, -51, 61, 91, 46, 40, -20, -43, 271, -2, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -2, -2, 41, -13, 271, -37, -26, 263, 265, -23, 44, 271, -52, -26, 271, -4, -5, 41, 44, -22, -38, -39, -7, 123, 91, 41, -2, -26, -15, -33, -42, -51, -26, 93, 41, -21, 271, -2, -26, -26, -8, -9, -44, 271, -10, -11, -46, -22, -2, -16, -34, -35, -3, -22, -27, 260, 261, 125, 44, -45, 93, 44, -47, -26, -2, 267, 266, 266, -22, -26, -44, 61, -48, 266, -4, 259, -26, -47, -16, -2, -22, -2, -27 }; int yydef[] = { 1, -2, 11, 4, 5, 0, 104, 13, 0, 6, 3, 14, 12, 0, 16, 18, 0, 21, 0, -2, 63, 94, 0, 0, 33, 0, 0, 0, 48, -2, 52, 53, 54, 55, 0, 0, 26, 0, 0, 22, 101, 0, 0, 0, 71, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 33, 0, 46, 47, 75, 61, 56, 0, 0, 9, 20, -2, -2, 0, 99, 102, 0, 0, 66, 0, 72, 73, 26, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 57, 59, 34, 0, 76, 0, 62, 32, 0, -2, 69, 101, 0, 0, 98, 0, 67, 7, 0, 32, 0, 0, 49, 79, -2, 50, 26, 32, 13, -2, 0, 100, 103, 96, 64, 26, 74, 23, 58, 60, 0, 80, 81, 83, 0, 86, 0, 32, 19, 10, 28, 0, -2, 0, 0, 26, 0, 77, 0, 0, 78, 89, 88, 91, 0, 66, 8, 15, 24, 0, 82, 0, 0, 17, 13, 32, 84, 90, 31, 26, 32, 23, 25 }; typedef struct { char *t_name; int t_val; } yytoktype; /* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */ /* ** Skeleton parser driver for yacc output */ /* ** yacc user known macros and defines */ #define YYERROR goto yyerrlab #define YYACCEPT { free(yys); free(yyv); return(0); } #define YYABORT { free(yys); free(yyv); return(1); } #define YYBACKUP( newtoken, newvalue )
  • 126. 126 { if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 ) { yyerror( "syntax error - cannot backup" ); goto yyerrlab; } yychar = newtoken; yystate = *yyps; yylval = newvalue; goto yynewstate; } #define YYRECOVERING() (!!yyerrflag) #ifndef YYDEBUG # define YYDEBUG 1 /* make debugging available */ #endif /* ** user known globals */ int yydebug; /* set to 1 to get debugging */ /* ** driver internal defines */ #define YYFLAG (-1000) /* ** static variables used by the parser */ static YYSTYPE *yyv; /* value stack */ static int *yys; /* state stack */ static YYSTYPE *yypv; /* top of value stack */ static int *yyps; /* top of state stack */ static int yystate; /* current state */ static int yytmp; /* extra var (lasts between blocks) */ int yynerrs; /* number of errors */ int yyerrflag; /* error recovery flag */ int yychar; /* current input token number */ /* ** yyparse - return 0 if worked, 1 if syntax error not recovered from */ int yyparse() { // register YYSTYPE *yypvt; /* top of value stack for $vars */ YYSTYPE *yypvt; /* top of value stack for $vars */ unsigned yymaxdepth = YYMAXDEPTH; /* ** Initialize externals - yyparse may be called more than once */
  • 127. 127 yyv = (YYSTYPE *) malloc(yymaxdepth * sizeof(YYSTYPE)); yys = (int *) malloc(yymaxdepth * sizeof(int)); if (!yyv || !yys) { yyerror("out of memory"); return (1); } yypv = &yyv[-1]; yyps = &yys[-1]; yystate = 0; yytmp = 0; yynerrs = 0; yyerrflag = 0; yychar = -1; goto yystack; { // register YYSTYPE *yy_pv; /* top of value stack */ YYSTYPE *yy_pv; /* top of value stack */ // register int *yy_ps; /* top of state stack */ int *yy_ps; /* top of state stack */ // register int yy_state; /* current state */ int yy_state; /* current state */ // register int yy_n; /* internal state number info */ int yy_n; /* internal state number info */ /* ** get globals into registers. ** branch to here only if YYBACKUP was called. */ yynewstate: yy_pv = yypv; yy_ps = yyps; yy_state = yystate; goto yy_newstate; /* ** get globals into registers. ** either we just started, or we just finished a reduction */ yystack: yy_pv = yypv; yy_ps = yyps; yy_state = yystate; /* ** top of for (;;) loop while no reductions done */ yy_stack: /* ** put a state and value onto the stacks */ if (++yy_ps >= &yys[yymaxdepth]) { /* room on stack? */ /* ** reallocate and recover. Note that pointers ** have to be reset, or bad things will happen */ int yyps_index = (yy_ps - yys);
  • 128. 128 int yypv_index = (yy_pv - yyv); int yypvt_index = (yypvt - yyv); yymaxdepth += YYMAXDEPTH; yyv = (YYSTYPE *) realloc((char *) yyv, yymaxdepth * sizeof(YYSTYPE)); yys = (int *) realloc((char *) yys, yymaxdepth * sizeof(int)); if (!yyv || !yys) { yyerror("yacc stack overflow"); return (1); } yy_ps = yys + yyps_index; yy_pv = yyv + yypv_index; yypvt = yyv + yypvt_index; } *yy_ps = yy_state; *++yy_pv = yyval; /* ** we have a new state - find out what to do */ yy_newstate: if ((yy_n = yypact[yy_state]) <= YYFLAG) goto yydefault; /* simple state */ if ((yychar < 0) && ((yychar = yylex()) < 0)) yychar = 0; /* reached EOF */ if (((yy_n += yychar) < 0) || (yy_n >= YYLAST)) goto yydefault; if (yychk[yy_n = yyact[yy_n]] == yychar) { /*valid shift */ yychar = -1; yyval = yylval; yy_state = yy_n; if (yyerrflag > 0) yyerrflag--; goto yy_stack; } yydefault: if ((yy_n = yydef[yy_state]) == -2) { if ((yychar < 0) && ((yychar = yylex()) < 0)) yychar = 0; /* reached EOF */ /* ** look through exception table */ { int *yyxi = yyexca; //register int *yyxi = yyexca; while ((*yyxi != -1) || (yyxi[1] != yy_state)) { yyxi += 2; } while ((*(yyxi += 2) >= 0) && (*yyxi != yychar)); if ((yy_n = yyxi[1]) < 0) YYACCEPT; }
  • 129. 129 } /* ** check for syntax error */ if (yy_n == 0) { /* have an error */ /* no worry about speed here! */ switch (yyerrflag) { case 0: /* new error */ yyerror("syntax error"); goto skip_init; yyerrlab: /* ** get globals into registers. ** we have a user generated syntax type error */ yy_pv = yypv; yy_ps = yyps; yy_state = yystate; yynerrs++; skip_init: case 1: case 2: /* incompletely recovered error */ /* try again... */ yyerrflag = 3; /* ** find state where "error" is a legal ** shift action */ while (yy_ps >= yys) { yy_n = yypact[*yy_ps] + YYERRCODE; if (yy_n >= 0 && yy_n < YYLAST && yychk[yyact[yy_n]] == YYERRCODE) { /* ** simulate shift of "error" */ yy_state = yyact[yy_n]; goto yy_stack; } /* ** current state has no shift on ** "error", pop stack */ yy_ps--; yy_pv--; } /* ** there is no state on stack with "error" as ** a valid shift. give up. */ YYABORT; case 3: /* no shift yet; eat a token */
  • 130. 130 if (yychar == 0) /* reached EOF. quit */ YYABORT; yychar = -1; goto yy_newstate; } } /* end if ( yy_n == 0 ) */ /* ** reduction by production yy_n ** put stack tops, etc. so things right after switch */ yytmp = yy_n; /* value to switch over */ yypvt = yy_pv; /* $vars top of value stack */ /* ** Look in goto table for next state ** Sorry about using yy_state here as temporary ** register variable, but why not, if it works... ** If yyr2[ yy_n ] doesn't have the low order bit ** set, then there is no action to be done for ** this reduction. So, no saving & unsaving of ** registers done. The only difference between the ** code just after the if and the body of the if is ** the goto yy_stack in the body. This way the test ** can be made before the choice of what to do is needed. */ { /* length of production doubled with extra bit */ // register int yy_len = yyr2[yy_n]; int yy_len = yyr2[yy_n]; if (!(yy_len & 01)) { yy_len >>= 1; yyval = (yy_pv -= yy_len)[1]; /* $$ = $1 */ yy_state = yypgo[yy_n = yyr1[yy_n]] + *(yy_ps -= yy_len) + 1; if (yy_state >= YYLAST || yychk[yy_state = yyact[yy_state]] != -yy_n) { yy_state = yyact[yypgo[yy_n]]; } goto yy_stack; } yy_len >>= 1; yyval = (yy_pv -= yy_len)[1]; /* $$ = $1 */ yy_state = yypgo[yy_n = yyr1[yy_n]] + *(yy_ps - = yy_len) + 1; if (yy_state >= YYLAST || yychk[yy_state = yyact[yy_state]] != -yy_n) { yy_state = yyact[yypgo[yy_n]]; } } /* save until reenter driver code */ yystate = yy_state; yyps = yy_ps; yypv = yy_pv;
  • 131. 131 } /* ** code supplied by user is placed in this switch */ switch (yytmp) { case 2: { pc = basepc = maincode; nlocalvar = 0; } break; case 3: { maincode = pc; } break; case 6: { pc = basepc = code; nlocalvar = 0; } break; case 7: { if (dfn_debug) { align(Word); code_byte(SETFUNCTION); code_word(yypvt[-5].vWord); code_word(yypvt[-4].vWord); } dfn_codeadjust(0); } break; case 8: { if (dfn_debug) code_byte(RESET); code_byte(RETCODE); code_byte(nlocalvar); s_tag(yypvt[-7].vWord) = T_FUNCTION; s_bvalue(yypvt[-7].vWord) = calloc(pc - code, sizeof(Byte)); memcpy(s_bvalue(yypvt[-7].vWord), code, (pc - code) * sizeof(Byte)); } break; case 11: { ntemp = 0; if (dfn_debug) { align(Word); code_byte(SETLINE); code_word(dfn_linenumber); } } break; case 15: { {
  • 132. 132 Byte *elseinit = yypvt[-2].pByte + sizeof(Word) + 1; if (pc - elseinit == 0) { /* no else */ pc -= sizeof(Word) + 1; /* if (*(pc-1) == NOP) --pc; */ elseinit = pc; } else { *(yypvt[-2].pByte) = JMP; *((Word *) (yypvt[-2].pByte + 1)) = pc - elseinit; } *(yypvt[-4].pByte) = IFFJMP; *((Word *) (yypvt[-4].pByte + 1)) = elseinit - (yypvt[-4].pByte + sizeof(Word) + 1); } } break; case 16: { yyval.pByte = pc; } break; case 17: { *(yypvt[-3].pByte) = IFFJMP; *((Word *) (yypvt[-3].pByte + 1)) = pc - (yypvt[-3].pByte + sizeof(Word) + 1); *(yypvt[-1].pByte) = UPJMP; *((Word *) (yypvt[-1].pByte + 1)) = pc - yypvt[-6].pByte; } break; case 18: { yyval.pByte = pc; } break; case 19: { *(yypvt[-0].pByte) = IFFUPJMP; *((Word *) (yypvt[-0].pByte + 1)) = pc - yypvt[-4].pByte; } break; case 20: { { int i; if (yypvt[-0].vInt == 0 || nvarbuffer != ntemp - yypvt[-2].vInt * 2) dfn_codeadjust(yypvt[-2].vInt * 2 + nvarbuffer); for (i = nvarbuffer - 1; i >= 0; i--) dfn_codestore(i); if (yypvt[-2].vInt > 1 || (yypvt[- 2].vInt == 1 && varbuffer[0] != 0)) dfn_codeadjust(0); }
  • 133. 133 } break; case 21: { dfn_codeadjust(0); } break; case 25: { { Byte *elseinit = yypvt[-1].pByte + sizeof(Word) + 1; if (pc - elseinit == 0) { /* no else */ pc -= sizeof(Word) + 1; /* if (*(pc-1) == NOP) --pc; */ elseinit = pc; } else { *(yypvt[-1].pByte) = JMP; *((Word *) (yypvt[-1].pByte + 1)) = pc - elseinit; } *(yypvt[-3].pByte) = IFFJMP; *((Word *) (yypvt[-3].pByte + 1)) = elseinit - (yypvt[-3].pByte + sizeof(Word) + 1); } } break; case 26: { yyval.vInt = nlocalvar; } break; case 27: { ntemp = 0; } break; case 28: { if (nlocalvar != yypvt[-3].vInt) { nlocalvar = yypvt[-3].vInt; dfn_codeadjust(0); } } break; case 30: { if (dfn_debug) { align(Word); code_byte(SETLINE); code_word(dfn_linenumber); } } break; case 31: { if (dfn_debug) code_byte(RESET); code_byte(RETCODE);
  • 134. 134 code_byte(nlocalvar); } break; case 32: { align(Word); yyval.pByte = pc; code_byte(0); /* open space */ code_word(0); } break; case 33: { if (yypvt[-0].vInt == 0) { dfn_codeadjust(ntemp + 1); incr_ntemp(); } } break; case 34: { yyval.vInt = yypvt[-1].vInt; } break; case 35: { code_byte(EQOP); yyval.vInt = 1; ntemp--; } break; case 36: { code_byte(LTOP); yyval.vInt = 1; ntemp--; } break; case 37: { code_byte(LEOP); code_byte(NOTOP); yyval.vInt = 1; ntemp--; } break; case 38: { code_byte(EQOP); code_byte(NOTOP); yyval.vInt = 1; ntemp--; } break; case 39: { code_byte(LEOP); yyval.vInt = 1; ntemp--; } break;
  • 135. 135 case 40: { code_byte(LTOP); code_byte(NOTOP); yyval.vInt = 1; ntemp--; } break; case 41: { code_byte(ADDOP); yyval.vInt = 1; ntemp--; } break; case 42: { code_byte(SUBOP); yyval.vInt = 1; ntemp--; } break; case 43: { code_byte(MULTOP); yyval.vInt = 1; ntemp--; } break; case 44: { code_byte(DIVOP); yyval.vInt = 1; ntemp--; } break; case 45: { code_byte(CONCOP); yyval.vInt = 1; ntemp--; } break; case 46: { yyval.vInt = 1; } break; case 47: { code_byte(MINUSOP); yyval.vInt = 1; } break; case 48: { code_byte(PUSHBYTE); yyval.pByte = pc; code_byte(0); incr_ntemp(); code_byte(CREATEARRAY);
  • 136. 136 } break; case 49: { *(yypvt[-2].pByte) = yypvt[-0].vInt; if (yypvt[-1].vLong < 0) { /* there is no function to be called */ yyval.vInt = 1; } else { dfn_pushvar(yypvt[-1].vLong + 1); code_byte(PUSHMARK); incr_ntemp(); code_byte(PUSHOBJECT); incr_ntemp(); code_byte(CALLFUNC); ntemp -= 4; yyval.vInt = 0; if (dfn_debug) { align(Word); code_byte(SETLINE); code_word(dfn_linenumber); } } } break; case 50: { code_byte(CREATEARRAY); yyval.vInt = 1; } break; case 51: { dfn_pushvar(yypvt[-0].vLong); yyval.vInt = 1; } break; case 52: { code_number(yypvt[-0].vFloat); yyval.vInt = 1; } break; case 53: { align(Word); code_byte(PUSHSTRING); code_word(yypvt[-0].vWord); yyval.vInt = 1; incr_ntemp(); } break; case 54: { code_byte(PUSHNIL); yyval.vInt = 1; incr_ntemp(); } break; case 55: {
  • 137. 137 yyval.vInt = 0; if (dfn_debug) { align(Word); code_byte(SETLINE); code_word(dfn_linenumber); } } break; case 56: { code_byte(NOTOP); yyval.vInt = 1; } break; case 57: { code_byte(POP); ntemp--; } break; case 58: { *(yypvt[-2].pByte) = ONFJMP; *((Word *) (yypvt[-2].pByte + 1)) = pc - (yypvt[-2].pByte + sizeof(Word) + 1); yyval.vInt = 1; } break; case 59: { code_byte(POP); ntemp--; } break; case 60: { *(yypvt[-2].pByte) = ONTJMP; *((Word *) (yypvt[-2].pByte + 1)) = pc - (yypvt[-2].pByte + sizeof(Word) + 1); yyval.vInt = 1; } break; case 61: { code_byte(PUSHNIL); incr_ntemp(); } break; case 63: { code_byte(PUSHMARK); yyval.vInt = ntemp; incr_ntemp(); } break; case 64: { code_byte(CALLFUNC); ntemp = yypvt[-3].vInt - 1; } break;
  • 138. 138 case 65: { dfn_pushvar(yypvt[-0].vLong); } break; case 66: { yyval.vInt = 1; } break; case 67: { yyval.vInt = yypvt[-0].vInt; } break; case 68: { yyval.vInt = yypvt[-0].vInt; } break; case 69: { if (!yypvt[-1].vInt) { dfn_codeadjust(ntemp + 1); incr_ntemp(); } } break; case 70: { yyval.vInt = yypvt[-0].vInt; } break; case 73: { localvar[nlocalvar] = yypvt[-0].vWord; incr_nlocalvar(); } break; case 74: { localvar[nlocalvar] = yypvt[-0].vWord; incr_nlocalvar(); } break; case 75: { yyval.vLong = -1; } break; case 76: { yyval.vLong = yypvt[-0].vWord; } break; case 77: { yyval.vInt = yypvt[-1].vInt; } break; case 78:
  • 139. 139 { yyval.vInt = yypvt[-1].vInt; } break; case 79: { yyval.vInt = 0; } break; case 80: { yyval.vInt = yypvt[-0].vInt; } break; case 81: { yyval.vInt = 1; } break; case 82: { yyval.vInt = yypvt[-2].vInt + 1; } break; case 83: { align(Word); code_byte(PUSHSTRING); code_word(dfn_findconstant(s_name(yypvt[- 0].vWord))); incr_ntemp(); } break; case 84: { code_byte(STOREFIELD); ntemp -= 2; } break; case 85: { yyval.vInt = 0; } break; case 86: { yyval.vInt = yypvt[-0].vInt; } break; case 87: { code_number(1); } break; case 88: { yyval.vInt = 1; } break; case 89: {
  • 140. 140 code_number(yypvt[-1].vInt + 1); } break; case 90: { yyval.vInt = yypvt[-3].vInt + 1; } break; case 91: { code_byte(STOREFIELD); ntemp -= 2; } break; case 92: { nvarbuffer = 0; varbuffer[nvarbuffer] = yypvt[-0].vLong; incr_nvarbuffer(); yyval.vInt = (yypvt[-0].vLong == 0) ? 1 : 0; } break; case 93: { varbuffer[nvarbuffer] = yypvt[-0].vLong; incr_nvarbuffer(); yyval.vInt = (yypvt[-0].vLong == 0) ? yypvt[- 2].vInt + 1 : yypvt[-2].vInt; } break; case 94: { int local = dfn_localname(yypvt[-0].vWord); if (local == -1) /* global var */ yyval.vLong = yypvt[-0].vWord + 1; /* return positive value */ else yyval.vLong = -(local + 1); /* return negative value */ } break; case 95: { dfn_pushvar(yypvt[-0].vLong); } break; case 96: { yyval.vLong = 0; /* indexed variable */ } break; case 97: { dfn_pushvar(yypvt[-0].vLong); } break; case 98: { align(Word); code_byte(PUSHSTRING);
  • 141. 141 code_word(dfn_findconstant(s_name(yypvt[- 0].vWord))); incr_ntemp(); yyval.vLong = 0; /* indexed variable */ } break; case 99: { localvar[nlocalvar] = yypvt[-1].vWord; incr_nlocalvar(); } break; case 100: { localvar[nlocalvar] = yypvt[-1].vWord; incr_nlocalvar(); } break; case 101: { code_byte(PUSHNIL); } break; case 102: { ntemp = 0; } break; case 104: { dfn_debug = yypvt[-0].vInt; } break; } goto yystack; /* reset registers in driver code */ } /* * y_tab.h */ typedef union { int vInt; long vLong; float vFloat; Word vWord; Byte *pByte; } YYSTYPE; extern YYSTYPE yylval; #define NIL 257 #define IF 258 #define THEN 259 #define ELSE 260
  • 142. 142 #define ELSEIF 261 #define WHILE 262 #define DO 263 #define REPEAT 264 #define UNTIL 265 #define END 266 #define RETURN 267 #define LOCAL 268 #define NUMBER 269 #define FUNCTION 270 #define NAME 271 #define STRING 272 #define DEBUG 273 #define NOT 274 #define AND 275 #define OR 276 #define NE 277 #define LE 278 #define GE 279 #define CONC 280 #define UNARY 281 #define ENDWHILE 300 #define ENDIF 301
  • 143. 143 APÊNDICE B – ARQUIVOS DE CONFIGURAÇÃO DO ASTERISK E MÓDULO DE CARGA ;; ;; Arquivo de configuração dos módulos do Asterisk ;; [modules] ; autoload habilitado, instrui o Asterisk a carregar todos os arquivos *.so que encontrar em /var/lib/asterisk/modules autoload=yes ; Cada módulo precisa ser carregado antes do núcleo do Asterisk ser inicializado. ; ; A linha abaixo só deverá ser descomentada se o autoload for igual a "no". ;load => pbx_dfn.so ; Como o autoload está habilitado, caso não se pretenda carregar o módulo da linguagem dfn, ; deve-se remover o comentário da linha abaixo ;noload => pbx_dfn.so Arquivo sip.conf: ; SIP Configuration - Asterisk ; Exemplo de configuração que será usada na demonstração do trabalho ; Este arquivo contém a autenticação dos ramais. ; [general] context=default ; Default context for incoming calls allowoverlap=no ; Disable overlap dialing support. (Default is yes) udpbindaddr=0.0.0.0 ; IP address to bind UDP listen socket to (0.0.0.0 binds to all) tcpenable=no ; Enable server for incoming TCP connections (default is no) tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0 binds to all interfaces) srvlookup=yes ; Enable DNS SRV lookups on outbound calls register => username:secret@host/callbackextension register => 1234:password@mysipprovider.com ; Ramais para teste [4001]
  • 144. 144 context=from-internal type=friend regexten=4001 ; When they register, create extension 1234 defaultuser=4001 secret=4001 callerid="CP" <4001> host=dynamic nat=no ; X-Lite is behind a NAT router canreinvite=no ; Typically set to NO if behind NAT disallow=all allow=g729 allow=ulaw allow=alaw allow=gsm ; GSM consumes far less bandwidth than ulaw ;allow=all permit=0.0.0.0/0.0.0.0 [4002] context=from-internal type=friend regexten=4002 ; When they register, create extension 1234 defaultuser=4002 secret=4002 callerid="CP" <4002> host=dynamic nat=no ; X-Lite is behind a NAT router canreinvite=no ; Typically set to NO if behind NAT disallow=all allow=g729 allow=ulaw allow=alaw allow=gsm ; GSM consumes far less bandwidth than ulaw ;allow=all permit=0.0.0.0/0.0.0.0 /* Modulo de carga para o Asterisk */ #include "asterisk.h" ASTERISK_FILE_VERSION(__FILE__, "$Revision: $") #include "asterisk/module.h" #include "asterisk/logger.h" #include "asterisk/pbx.h" #include "asterisk/paths.h" /* ast_config_AST_CONFIG_DIR */ #include "dfn/dfn.h" #include "dfn/dfnlib.h" static char *config = "extensions.dfn";
  • 145. 145 //static char *registrar = "pbx_dfn"; static int pbx_load_module(void); static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); static struct ast_switch dfn_switch = { .name = "DFN", .description = "DFN Language PBX Switch", .exists = exists, .canmatch = canmatch, .exec = exec, .matchmore = matchmore, }; static int pbx_load_module(void) { char *rfilename; if (config[0] == '/') rfilename = (char *)config; else { rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config); } if (access(rfilename,R_OK) != 0) { ast_log(LOG_NOTICE, "File %s not found; DFN Extension Language module declining loadn", rfilename); return AST_MODULE_LOAD_DECLINE; } dfn_execfile(rfilename); ast_log(LOG_NOTICE, "DFN Extension Language Loadedn"); return AST_MODULE_LOAD_SUCCESS; } static int load_module(void) { ast_log(LOG_NOTICE, "Starting DFN Extension Language load process.n"); return (pbx_load_module()); } static int unload_module(void)
  • 146. 146 { ast_log(LOG_NOTICE, "DFN Extension Language Unloadedn"); return 0; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DFN Extension Language");
  • 147. 147 APÊNDICE C – ARQUIVO DE CONFIGURAÇÃO DO XEN # # Arquivo de configuração da máquina virtual a ser usada no trabalho # kernel = "/images/TCC/boot/vmlinuz-xen" ramdisk = "/images/TCC/boot/initrd-xen" builder='linux' memory = 512 name = "TCC_VM_DFN" #uuid = "06ed00fe-1162-4fc4-b5d8-11993ee4a8b9" # Number of Virtual CPUS to use, default is 1 vcpus = 1 vif = [ 'mac=00:16:3e:00:00:11, bridge=br0' ] disk = [ 'file:/images/TCC/vdisks/sda_vdisk_12GB.img,xvda,w', 'file:/images/TCC/vdisks/sdb_vdisk_16GB.img,xvdb,w' ] root = "/dev/xvda2" vfb = [ 'vnc=1,vnclisten=0.0.0.0,vncunused=1,vncpasswd=reurbanisatus' ] # Set root device. #root = "/dev/hda1" # Extra arguments to pass to the kernel. extra = "xencons=xvc console=xvc0 video=tty" #on_poweroff = 'destroy'