Examensarbete. Kompilator system för integration av SQL- databas i Ada- baserat system genom ODBC



Relevanta dokument
lex källkod lex.l lexkompilator lex.yy.c C- kompilator lex.yy.c a.out sekvens av tokens a.out input specifikation av tokens mha reguljära uttryck

Föreläsning 6: Introduktion av listor

Att använda pekare i. C-kod

Introduktion till integrering av Schenkers e-tjänster. Version 2.0

Dagens föreläsning. Repetition. Repetition - Programmering i C. Repetition - Vad C består av. Repetition Ett första C-program

Programmeringsteknik med C och Matlab

Sockets: server. with Ada.Command_Line; use Ada.Command_Line; with Ada.Exceptions; use Ada.Exceptions; with Ada.Text_IO; use Ada.

Hjälpmedel för kompilatorkonstruktion, DVB004

Tentamen Grundläggande programmering

Programmeringsteknik med C och Matlab

Övning från förra gången: readword

Översikt. Installation av EasyPHP 1. Ladda ner från Jag använder Release Installera EasyPHP.

INTRODUKTION TILL JDBC

Introduktion till arv

Föreläsning 4: Poster

Tentamen OOP

1 Funktioner och procedurell abstraktion

Tentamen i. för D1 m fl, även distanskursen. fredag 13 januari 2012

Programmering A. Johan Eliasson

Objektorienterad programmering D2

Föreläsning 2: Avlusning och antilustekniker

WCMS-15, Webbutvecklare CMS

Dagens föreläsning. Repetition. Repetition - Programmering i C. Repetition - Vad C består av. Repetition Ett första C-program

Elektroteknik MF1016 föreläsning 9 MF1017 föreläsning 7 Mikrodatorteknik

Övningar Dag 2 En första klass

Hur man kompilerar och kör IT++-program med MinGW. 1 Sammanfattning. 2 Om dokumentet. 3 Om min konfiguration

TDDI02. Programmeringsprojekt. Föreläsning 3 Jonas Lindgren, Institutionen för Datavetenskap, LiU

5 Grundläggande in- och utmatning

Programmeringsuppgifter 1

1. PLSQL 2 2. Select into

Chapter 3: Using Classes and Objects

Sätt att skriva ut binärträd

Lösningar till tentauppgifterna sätts ut på kurssidan på nätet idag kl 19. Omtentamen i Programmering C, 5p, fristående, kväll,

Databasutveckling Introduktion till SQL och TSQL

Lösningsförslag, tentamen FYTA11 Javaprogrammering

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

Du skall naturligtvis visa körexempel med output där det behövs i din rapport!

Objektorienterad programmering i Java

Extra övningar på SDD:er/SDT:er

SMD 134 Objektorienterad programmering

Beijer Electronics AB 2000, MA00336A,

GU / Chalmers Campus Lindholmen Tentamen Programutveckling LEU 482 / TIG167

PROGRAMMERING A VC# 2008 EXPRESS UTVECKLINGSVERKTYGET VISUAL C#

TDIU01 - Programmering i C++, grundkurs

Denna laboration skapades för elever vid Roslagens Högskola men kan användas av vem som helst. Namnen på servrarna måste i så fall ändras.

Skizz till en enkel databas

Klientprogrammering mot databaser

Exempel på ett litet Ada-program

Föreläsning 5: Introduktion av pekare

Enkla datatyper minne

Pekare och arrayer. Indexering och avreferering

Programmering A C# VT Ett kompendie över Programmering A (50p) i c# Stefan Fredriksson

Tentaupplägg denna gång

Prova på-laboration i PHP Johan Sjöholm johsj@ida.liu.se Institutionen för datavetenskap, Linköpings universitet

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Programmera i C Varför programmera i C när det finns språk som Simula och Pascal??

Innehållsförteckning. Exempel. Åtkomst & användarhandledning

Smartair System. TS1000 Version 4.23

Arbeta med databas. Översikt. Lektion 1: Arbeta med Entity Data Models. Arbeta med Entity Data Models. LINQ (Language Integrated Query).

Innehåll MySQL Intro. Allmänt om Lagrade Procedurer Enkel utformning Skapa en lagrad procedur Använda parameter som indata

Exempelsamling Assemblerprogrammering

Föreläsning 2 Objektorienterad programmering DD1332. Typomvandling

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Kapitel 15: Data/Matrix Editor

Vyer, Prepared Statements, Triggers

Föreläsning 3.1: Datastrukturer, en översikt

Introduk+on +ll programmering i JavaScript

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Klassdeklaration. Metoddeklaration. Parameteröverföring

TDDC74 Programmering: Abstraktion och modellering Dugga 2, , kl 17-19

printenv sort pager printenv grep args sort pager

Design och underhåll av databaser

Att skriva till och läsa från terminalfönstret

Uppgift (poäng) 1 (2) 2 (3) 3 (4) 4 (4) 5 (3) 6 (4) 7 (6) 8 (6) 9 (8) Summa

Föreläsning 7: Syntaxanalys

Uppgift 1 ( Betyg 3 uppgift )

Växtviskaren EITF11 Digitala projekt VT15, I12

Introduktion Schenker-BTL AB, Stab IT Beskrivning över informationsintegreringmed Schenker, metodbeskrivning version 1.

ANVÄNDARMANUAL. handdatorer i ängs- och betesmarksinventeringen. för

Grundläggande programmering med C# 7,5 högskolepoäng

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

Lär känna MS SQL 2008 / Övning. Observera. Tips. Förberedelse

Föreläsning 1 & 2 INTRODUKTION

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

725G61 - Laboration 7 Implementation av ett API. Johan Falkenjack

Programsystemkonstruktion med C++: Övning 1. Karl Palmskog september 2010

Tänk på följande: Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Tentamen TEN1 HI

Inlämningsuppgift MiniPlotter

Objektsamlingar i Java

Snabbguide Visma Compact API Version 5.1 Copyright Visma Spcs AB Visma Compact API

Typkonvertering. Java versus C

Dagens föreläsning Programmering i Lisp. - Bindning av variabler (avs 14.6) fria variabler statisk/lexikalisk och dynamisk bindning

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Muddy. Funktioner / metoder. Punktnotation. Evalueringsordning

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

TENTAMEN. Kurs: Objektorienterad programmeringsmetodik 5DV133 Ansvarig lärare: Anders Broberg. VT-13 Datum: Tid: kl

Föreläsning 5 (6) Metoder. Metoder Deklarera. Metoder. Parametrar Returvärden Överlagring Konstruktorer Statiska metoder tostring() metoden javadoc

TENTAMEN DATABASKUNSKAP ITEK12

1.Lär känna MS SQL Observera. Tips. Förberedelse

PROGRAMMERING 2 GRUNDLÄGGANDE SEMANTIK 4

Transkript:

Mälardalens högskola Institutionen för Datateknik Examensarbete datalogi nivå C Examinator: Christer Norström Företag: Celciustech AB, Järfälla Handledare: Anders Jansson Examensarbete Kompilator system för integration av SQL- databas i Ada- baserat system genom ODBC Järfälla 2000-08-25 Monica Larsson mln99005@student.mdh.se David Löfqvist dlt99001@student.mdh.se

Förord Vi vill tacka företaget CelsiusTech AB som gav oss möjligheten att utföra vårt Examensarbete hos dem. Det mesta på företaget så som maten, medarbetare, arbetsrum var bra. Ett speciellt tack går till vår handledare Anders Jansson och initiativtagaren till exjobbet Daniel Wengelin. Även Hugo Löving som hoppade in som vår handledare när Anders Jansson var borta skall ha ett tack. En olycklig omständighet var att den tilltänkta handledaren slutade innan vi hann komma igång med examensarbetet. Han var den som var mest insatt i de områden som examensarbetet innefattar. Hans kunskap och förståelse för hur systemet är uppbyggt och fungerar idag skulle ha underlättat mycket i analysen av problemet, samt säkert förkortat inlärnings samt förståelsetiden för oss. Förmodligen skulle han med sin förståelse också kunnat ge oss värdefulla tips och förslag på lösningar på de problem vi stötte på vid implementationen av kompilatorsystemet. Kanske inte implementations mässigt men på en mer abstrakt nivå, som kanske skulle ha lett till ett mer robust och smartare kompilatorsystem. Istället blev det Anders Jansson som fick hoppa in som handledare. Han visade sig vara väldigt allround och duktig på det mesta. Men någon vecka efter det att vi satt igång med examensarbetet fick Anders ett erbjudande om ett nytt jobb vilket resulterade i att han sa upp sig. Detta faktum verkar dock inte haft någon större positiv/negativ inverkan på hur han handledde oss. Det som dock påverkade negativt var att han hade väldigt mycket att göra jämt och att han inte hann installera ODBC programvaran innan han gick på semester. Detta ledde till ett glapp på 2-3veckor då problemet med kopplingen mellan Ada och ODBC inte kunde arbetas på. Istället lades all energi på kompilatorsystemet vilket var ineffektivt. Någon vecka innan Anders kom tillbaka från semestern undersöktes hur ODBC fungerar. Detta gjordes för att snabbt komma igång med testningen av Ada till ODBC kopplingen när väl Anders kommit tillbaka. När Anders kom tillbaka tog han genast tag i problemet. Efter vissa problem vid installationen och konfigureringen av ODBC började det fungera.

Sammanfattning Examensarbetet har utförts på bl.a. CelsiusTech System AB eller numera Saab Tech Systems i Järfälla. På CTS utvecklas ett system som simulerar omvärlden till det operativa ledningssystemet av typ STRIC, främst i syfte att ge personalen i STRIC möjlighet att öva på sina uppgifter. Övningarna sker i förpreparerade spel vilka lagras i en databas och sedan vid övningstillfället läses in och exekveras i realtid. Vad som simuleras är Tex. radardata, flyg, marin etc. För att integrera simuleringsapplikationerna med databasen används ett definitionsspråk, SAMeDL, i vilken databasfrågorna definieras. En prekompilator (SAME) genererar Ada- kod och C- kod med embedded SQL. Den implementation av SAMeDL som används idag är behäftad med en hel del fel som måste åtgärdas genom efterbearbetning av den genererade koden. Det är här examensarbetet kommer in för att om möjligt lösa problemen med dagens tillvägagångssätt. Till skillnad från nuvarande implementation skall ett kompilatorsystem generera Ada kod för en ODBC gränsyta snarare än C och embedded SQL kod för en CT-lib gränsyta. Efter en analys av SAMeDL bestämdes det att ett eget kompilatorsystem byggt med hjälp av Lex och Yacc var lösningen på problemet. Lex och Yacc är program som används för att bygga upp kompilatorsystem. Det kompilatorsystem som utvecklades kan hantera syntaxen i de flesta av input filerna (SME-filerna), samt generera output i form av Ada kod. Ada koden anropar databasen genom en ODBC gränsyta. Lösningen med ODBC som gränsyta mot databasen ger ett standardiserat och flexiblare system, vilket gör att man utan problem kan byta ut vilken typ av databas som skall användas. På grund av tidsbrist klarar kompilatorsystemet bara att generera komplett output för en SME fil. Dock finns det inget som säger att det skulle vara svårt eller omöjligt att generera kompletta output filer för alla SME filer. Det som menas med kompletta output filer är att dessa filer skall generera exakt samma resultat som innan ombyggnationen av systemet, men utan efterbearbetning av fel.

Innehållsförteckning BAKGRUND...5 SYFTE...6 AVGRÄNSNINGAR...6 KONVENTIONER...6 FÖRKORTNINGAR...6 PROBLEMBESKRIVNING...7 PROBLEMANALYS...7 ADA...7 ODBC...7 UTVECKLINGSMILJÖ...10 ÖVERSIKTLIG BESKRIVNING AV NUVARANDE SYSTEM... 11 SAME...11 VARFÖR BEHÖVS SAME?...11 MÅL... 12 METOD... 12 LÖSNING... 13 INPUTFILERNAS (*.SME) EGENSKAPER...13 PRAKTISKT GENOMFÖRANDE...13 ADA TILL ODBC LÖSNING...21 RESULTAT... 25 FRAMTIDA ARBETE... 25 LITTERATURFÖRTECKNING... 26 BILAGA1...1 FLEX OCH BISON INTRODUKTION...1 Flex...1 Bison...2 BILAGA2...1 EN *.SME FILS UPPBYGGNAD...1 DBIF_DDD.SME FILENS ÖVERSIKTLIGA UPPBYGGNAD MED KOMMENTARER....2 S_DB.SME FILENS ÖVERSIKTLIGA UPPBYGGNAD MED KOMMENTARER....3 FLEX- FUNKTIONER...3 BISON...10 GRAMMATIK BISON...10 C- KODS DEL BISON...14 Figurförteckning FIGUR 1: DELAR I SIMULERINGEN...5 FIGUR 2: ODBC ETT GRÄNSSNITT MELLAN APPLIKATIONER OCH DATABASER...7 FIGUR 3: NUVARANDE SYSTEM...11 FIGUR 4: MÅLSYSTEMETS UPPBYGGNAD...12

Bakgrund Strics är ett system som simulerar omvärlden till det operativa ledningssystemet av typ STRIC, främst i syfte att ge personalen i STRIC möjlighet att öva på sina uppgifter. Övningarna sker i förpreparerade spel vilka lagras i en databas och sedan vid övningstillfället läses in och exekveras i realtid för att generera simulerat radardata etc. System Strics använder en relationsdatabas, Sybase, för att lagra data. Prepareringen sker med Javaoch 4GL- applikationer. Simuleringsapplikationerna är främst skrivna i Ada95. Plattformen för exekvering av övningarna är IBM/6000 med operativsystemet AIX, en Unix- variant. För att integrera simuleringsapplikationerna med databasen används ett definitionsspråk, SAMeDL, i vilken databasfrågorna definieras. En prekompilator genererar Ada- kod och C- kod med embedded SQL: Den implementation av SAMeDL som används idag är behäftad med en hel del fel som måste åtgärdas genom efterbearbetning av den genererade koden. 890 JAS/JA37 Flygbaser LIFV Flygbaser LIFV FK stab MILMET RTD RS D SU Radio FY L STRIC SYSIM 1-2 STRIC Telefoni ATC LULIS LC LV FIGUR 1: DELAR I SIMULERINGEN. lfc typ 1 LV-ordersändare LVrb 5

Syfte Examensarbetet består i att genom en analys av SAMeDL definiera, implementera och testa ett kompilatorsystem. Till skillnad från nuvarande implementation ska kompilatorsystemet generera Ada kod för en ODBC- gränsyta snarare än C och embedded SQL för en CT-lib gränsyta. ODBC gränssnittet ska även det implementeras och testas. Förslagsvis används LEX/YACC för att generera Ada95- kod. Alternativt används något scriptspråk för att implementera kompilatorn. Avgränsningar När vi i började med lex & yacc, så fick vi problem. Se i förordet. Detta gjorde att på slutet så fick vi avgränsa oss mer än vad vi önskade. Grammatiken för kompilatorn är skriven för ett fåtal av *.smefilerna. Konventioner Förkortningar Ada = Ada är ett högnivåspråk DB = DataBase DBIF = DataBase InterFace Interface mellan Ada applikationer och databasen DBMS = DataBase Management System ODBC = Open Database Connectivity standardiserat databasinterface SQL = Structured Query Language, ett standardiserat språk som används för att kommunicera med en relationsdatabas. SAME = SQL Ada Module Extension En metod för att skapa ett gränssnitt mellan Ada och SQL databaser. SAME består av ett antal Ada support paket. SAMeDL = SQL Ada Module Extension Description Language Ett språk för automatisk generering av SAME interface SME = Handskrivna input filer till SAME STRIC = Är ett nytt svenskt luftförsvarssystem STICS = Är ett system som simulerar omvärlden till det operativa ledningssystemet av typ STRIC 6

Problembeskrivning 1: Det nuvarande gränssnittet mot databasen består av ett CT- lib, som nu upplevs som gammalmodigt. Det gör tex. systemet bundet vid en viss sorts produkt av databas och ett visst språk. 2: Den nu använda produkten för kompilering av SAMeDL och handhavandet av denna är något trög, med ett flertal moment av handpåläggning. Exempelvis är SAMeDL behäftad med en hel del fel som måste åtgärdas genom efterbearbetning av den genererade koden vilket gör systemet långsamt. Problemanalys För att få ett mer flexibelt och modernare system skall CT-lib ersättas av ODBC och all C-kod som används för att anropa CT-lib skall ersättas av Ada-kod som anropar ODBC. Problemet kan delas upp i ett antal mindre delar: För att lösa problemet med att ersätta dagens C/CT-lib gränssnitt mot ett ADA/ODBC gränssnitt måste ett sätt att få fram ADA/ODBC kod tänkas ut. Går det att byta ut det befintliga sättet som används idag med en egen kompilatorlösning? Lex och yacc ska testas för att se om en kompilator kan byggas som ska tolka SME syntaxen och parsa fram motsvarande Ada samt ODBC kod, skriven i Ada. Ada En undersökning som skulle ta reda på om det finns Ada till ODBC kopplingar utfördes. Denna gav som resultat att det finns flera, T.ex. Iodbc ett freeware samt Datadirect från företaget MERANT. Men hur fungerar dessa då? För att få svar på den frågan gjordes en prototyp där Iodbc användes, prototypen gav svaret att det går att från Ada anropa ODBC. Finns det tillräcklig information I SME filerna för att kunna parsa fram all nödvändig Ada kod? För att hitta svaret på den frågan undersöktes hur dagens system fungerar. Det visade sig att den information som behövdes fanns i några olika filer som beskriver vilka tabeller, typer etc. som finns i databasen. Odbc För att genom ODBC kunna anropa en databas krävs viss kunskap om hur ODBC fungerar. Här följer en liten introduktion till ODBC. ODBC är ett standardiserat programmeringsgränssnitt för databasåtkomst. ODBC arkitekturen är uppbyggd för komponentbaserad databasåtkomst, vilket ger en logisk separation av applikationer och databaser (se figur 2). Applikation Applikation Applikation ODB DBM DBM DBM FIGUR 2: ODBC ETT GRÄNSSNITT MELLAN APPLIKATIONER OCH DATABASER. 7

ODBC är designat för att ge applikationer åtkomstmöjlighet till olika databaser utifrån samma källkod. Databasapplikationer anropar funktioner som finns inbakade I ODBC drivrutinerna. Användningen av drivrutinerna isolerar applikationerna från databasspecifika anrop, på samma sätt som drivrutiner för skrivare isolerar ordbehandlar program från skrivarspecifika kommandon. Tack vare att drivrutinerna laddas vid run-time kan man genom att lägga till en ny drivrutin få åtkomst till nya databaser, utan att behöva kompilera om applikationen. Nedan följer ett litet ODBC exempel. Några av dessa punkter är ej nödvändiga för att anropa en databas men de finns med för att ge ett utförligare exempel. 1. Det första man behöver är en variabel av typen SQLHENV. Den variabeln är handtaget till en intern ODBC struktur som innehåller all information om ODBC s environment. 2. Sätt environmentattribut som Tex. vilken ODBC version om det behövs. 3. Allokera ett anslutningshantag som används för att ansluta till databasen. 4. Sätt anslutningsattribut som Tex. timeout. 5. Anslut till databasen 6. Allokera ett statementhantag som är ett hantag till det statement som skall utföras 7. Bind kolumner till att lägga resultatet av SQL frågan i. 8. Exekvera statement 9. Räkna antalet kolumner som frågan resulterade i. 10. Räkna antalet rader som frågan resulterade i. 11. Hämta och skriv ut resultatet från kolumnerna. 12. Frigör resurser. ODBC exempel skriven i C: /* odbc.c */ #include <stdlib.h> #include <stdio.h> #include <odbc/sql.h> #include <odbc/sqlext.h> #include <odbc/sqltypes.h> SQLHENV V_OD_Env /* Handle ODBC environment */ long V_OD_erg /* result of functions */ SQLHDBC V_OD_hdbc /* Handle connection */ char V_OD_stat[10] /* Status SQL */ SQLINTEGER V_OD_err,V_OD_rowanz,V_OD_id SQLSMALLINT V_OD_mlen,V_OD_colanz char V_OD_msg[200],V_OD_buffer[200] int main(int argc,char *argv[]) /* 1. Allocate Environment handle and register version */ 8

V_OD_erg=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&V_OD_Env) /*2. Set some environment attributes */ V_OD_erg=SQLSetEnvAttr(V_OD_Env, SQL_ATTR_ODBC_VERSION, (void*)sql_ov_odbc3, 0) /* 3. Allocate connection handle */ V_OD_erg = SQLAllocHandle(SQL_HANDLE_DBC, V_OD_Env, &V_OD_hdbc) /*4. Set some connection attributes */ SQLSetConnectAttr(V_OD_hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0) /* 5. Connect to the data source "web" */ V_OD_erg = SQLConnect(V_OD_hdbc, (SQLCHAR*) "web", SQL_NTS, (SQLCHAR*) "christa", SQL_NTS, (SQLCHAR*) "", SQL_NTS) printf("connected!\n") /*6. Allocate statement handle */ V_OD_erg=SQLAllocHandle(SQL_HANDLE_STMT, V_OD_hdbc, &V_OD_hstmt) /*7. Bind columns to put result of SQL query in */ SQLBindCol(V_OD_hstmt,1,SQL_C_CHAR, &V_OD_buffer,150,&V_OD_err) SQLBindCol(V_OD_hstmt,2,SQL_C_ULONG,&V_OD_id,150,&V_OD_err) /*8. Execute statement */ V_OD_erg=SQLExecDirect(V_OD_hstmt,"SELECT dtname,iduser FROM tkeyuser order by iduser",sql_nts) /*9. Count result columns */ V_OD_erg=SQLNumResultCols(V_OD_hstmt,&V_OD_colanz) printf("number of Columns %d\n",v_od_colanz) /*10. Count result rows */ V_OD_erg=SQLRowCount(V_OD_hstmt,&V_OD_rowanz) printf("number of Rows %d\n",v_od_rowanz) /*11. Fetch the result from the columns and print it */ V_OD_erg=SQLFetch(V_OD_hstmt) while(v_od_erg!= SQL_NO_DATA) printf("result: %d %s\n",v_od_id,v_od_buffer) V_OD_erg=SQLFetch(V_OD_hstmt) /*12. Free resources */ SQLFreeHandle(SQL_HANDLE_STMT,V_OD_hstmt) SQLDisconnect(V_OD_hdbc) SQLFreeHandle(SQL_HANDLE_DBC,V_OD_hdbc) SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env) return(0) 9

Utvecklingsmiljö Uppgiften skall lösas på IBM/6000 med operativsystemet AIX, en Unix- variant. Språken som skall användas är C, Ada, SAMeDL, Embedded SQL, ODBC samt Lex och yacc. Eventuellt skall flex och bison som är gnu versioner av lex och yacc användas. Eftersom vi inte har så stora kunskaper inom något av dessa områden eller språk förutom i C kan detta visa sig vara en besvärlig tröskel att komma över. 10

Översiktlig beskrivning av nuvarande system SME-fil Embedded SQL Ada-body Adaspecifikation Applikationer C-kod CT-lib Visar kod genereringen Databas Visar anrops kedjan FIGUR 3: NUVARANDE SYSTEM. SAME SAME är en metod för att designa gränssnittet mellan applikationen, som är skriven i Ada95, och SQL, som används för att kommunicera med en relationsdatabas. SAMeDL är ett DBMS- oberoende språk som beskriver applikationens behov av databasgränssnitt. SAMeDL koden genererar, när den kompileras Ada-kod åt applikationshållet och C-kod ner mot databasen. Varför behövs SAME? Strics applikationen är skriven i språket Ada95. Varje systemenhet i applikationen, som har behov av databas data skriver en SAMeDL- specifikation. SAMeDL- specifikationen är handskriven och har suffixet *.sme, den fungerar som input till SAME. Från *.sme genereras motsvarande Ada- kod + C- kod. C- koden fungerar med CT-lib. 11

Mål SME-fil Ada-body Adaspecifikation Applikationer ODBC Databas Visar kod genereringen Visar anrops kedjan FIGUR 4: MÅLSYSTEMETS UPPBYGGNAD. Att från *.sme filerna generera ADA kod samt i den genererade Ada koden lägga till ODBC anrop istället för embedded sql och c-kods anrop till databasen Metod Databasgränssnittet ODBC undersöks och analyseras. Kan CT- lib bytas ut mot ODBC, vad är då värdet av detta? Utgångs ODBC är en freeware, eventuellt kommer en ODBC- applikation köpas in senare, under arbetets gång. En undersökning och utvärdering ska göras av värdet av att ersätta SAME med annan process. Kan *.sme filerna(eller eventuell den nya notationen) kompileras och på detta sätt generera Ada95 kod. Ada95 koden ska då kunna kommunicera med ODBC gränssnittet utan vidare transformering. På uppmaning av examensarbetets initiativtagare, Daniel Wengelin, så har en utvärdering av An Automatic Object- Oriented Parser Generator for Ada (AdaGOOP) gjorts. Eftersom parseträdet som AdaGOOP producerar har som input ada95 så är dock inte denna produkt aktuell, den aktuella applikationen har *.sme filer som input(samedl). En utvärdering av Aflex- An Ada Lexical Analyzer och Ayacc User s Manual har också gjorts. Skillnaden mellan lex och aflex samt yacc och ayacc är den att genererade filer som handhar den lexikaliska analysen respektive parsningen är skrivna i Ada. Vi är ännu ej så hemma på Ada och föredrar lex och yacc, då den är skriven i språket C, som vi är mer bekanta med. Eventuellt kommer FLEX och Bison som är gnu- versioner av lex och yacc användas om det ger större utvecklings möjligheter eller lättare lösning på problemet. 12

Lösning Inputfilernas (*.sme) egenskaper En *.sme fil (input filen) innehåller inte tillräcklig information för att generera *.ads och *.adb direkt, utan även Dbif_DDD.sme och S_db.sme måste parsas. Dbif_DDD..sme är en fil som håller alla i databasens förekommande variablers egenskaper. S_db.sme är en fil som håller alla i databasen förekommande databastabeller och dess struktur. Exempel på *.sme fil dessa tre filer visas i bilaga2.. Praktiskt genomförande Applikationen består av fyra filer, big.bison, big.flex, makefile och link.h big.flex s struktur med förklarande kommentarer inom /*...*/ : % /* början på definitionsdel */ #include <stdio.h> #include <string.h> #include <ctype.h> #include "big.bison.tab.h" #include "link.h" /* lineno håller reda på vilken aktuell rad i *.sme- filen som parsas */ /* with_counter räknar hur många with- förekomster som finns i aktuell *.sme- filen. Beroende /*på antalet with genereras olika with- block till *.ads och *.adb */ /*************************** counters **********************************************/ int lineno = 1 /* keeps track on line in inputfile */ int with_counter = 0 /* keeps track on occurenses of with */ /* Olika flaggor, som signalerar när ett keyword, id eller tecken ska sparas, signalerar även så att */ /* korrupt data ej sparas. Sparat data används då keyword, id eller tecken genereras i *.ads */ /* eller *.adb- filen */ /* OBS! Flera flaggor har tagits bort för att förenkla i rapporten */ /*********** different flags that signals when to save and **************************/ /*********** prevents the struct- arrays to hold corrupt data********************/...int signal3 = -1 /* signals when to save a procedures name used in *.adb */ int alarm = -1 /* signal when to save variables type used in *.ads */ int alarm4 = -1 /* signals when to save variables type in records body */ int alarm5 = -1 /* signals when to save variables type in cursors input */... /* Olika index, som räknas upp när ett keyword, id eller tecken har sparats undan i struct- arrayen */ /* OBS! Flera index har tagits bort för att förenkla */ /************ different index to keep track in struct- array*******************/... int odd2 = 1 /* used in sql_type() */ int cu2 = 0 /* index in curs_variables_type */ int sqllen = 0... /* Struct- arrayerna används för att spara undan tokens när det */ /* är nödvändigt, används för att genereras sedan i *.ads eller *.adb- filen */ /* OBS! Flera arrayer har tagits bort för att förenkla */ /********struct arrays that saves data that is used later when generating *.ads and *.adb ******/... struct inp_curs curs_sql_type[200] /* is used to save the Cursors variables SQL_type, is used later in *.adb */ struct inp_curs procedure_name[20] /* is used to save a name off procedure */... /* Hur flaggor, index och struct- arrayer fungerar redovisas nedanför i C- kods */ % /* slut på del som kopieras ordagrant till lex.yy.c*/ 13

/* Här anges hur ett token kan vara uppbyggt */ delim [ \t] /* delim är tab och mellanslag */ WS delim+ /* WS är en eller fler delims */ LETTER [A-Za-z] /* bokstäver */ UND [_] /* enskilda tecken som särskiljs */ DOT [.] PAR_ONE [(] PAR_TWO [)] COL [:] QUO ["] ATOM [,] DIGIT [0-9] /* siffror*/ ID LETTER(LETTER DIGIT UND DOT)* /* En godkänd variabel börjar med minst en bokstav, sedan versaler, gemener, siffror,., _ */ COMMENT "--"(.)*\n /* En kommentar börjar med -- sedan kommer vad-som-helst samt avslutas med nyradstecken */ N "NULL" /* NULL och NOT NULL särskiljs */ NN "NOT NULL" %% /* slut på definitions delen */ /* Regel del. OBS! Delar av aktions har tagits bort har för att förenkla, anges... */ WS COMMENT lineno++ /* radnr i *.sme fil räknas upp */ N strcpy(yylval.yystring,yytext)return N NN...strcpy(yylval.yystring,yytext) return NN /*Enskilda tecken som särskiljs. yytext[0] returneras till parsern dvs. det tecken som är det */ /* associerade värdet till aktuellt token */ PAR_ONE... if(alarm5 == 1) alarm5 = 2 return yytext[0] PAR_TWO return yytext[0] COL if(alarm4 == 2) alarm4 = 3... return yytext[0] QUO alarm5 = 0... if(alarm == 1) alarm = 0 return yytext[0] ATOM... return yytext[0] \n lineno++ /* radnr i *.sme fil räknas upp */ /* Nyckelorden definieras. Returvärdet är ett heltalsvärde som deklarerats som token i bisons */ /* specifikations- fil. Vid strcpy(yylval.yystring,yytext) så kopieras yytext-värdet till yylval.yystring */ /* som är en omdefinierad variabel yylval. yylval kan ses som en kommunikationsmöjlighet*/ /* mellan flex och bison. Dvs. inte enbart det returnerade heltalsvärdet av token är synligt i bison */ /* utan också tokens associerade värde */ abstract strcpy(yylval.yystring,yytext) return ABSTRACT and strcpy(yylval.yystring,yytext) return AND authorization by close_cursor... signal3 = 0 strcpy(yylval.yystring,yytext) return CLOSE_CURSOR close strcpy(yylval.yystring,yytext) return CLOSE cursor strcpy(yylval.yystring,yytext) return CURSOR Cursor... alarm5 = 1 alarm = 1 strcpy(yylval.yystring,yytext) return CURSOR delete strcpy(yylval.yystring,yytext) return DELETE get... signal3 = 0 strcpy(yylval.yystring,yytext) return GET get_is strcpy(yylval.yystring,yytext) return GET_IS end strcpy(yylval.yystring,yytext) return END fetch strcpy(yylval.yystring,yytext) return FETCH for... strcpy(yylval.yystring,yytext) return FOR from... strcpy(yylval.yystring,yytext) return FROM FROM strcpy(yylval.yystring,yytext) return FROM 14

insert strcpy(yylval.yystring,yytext) return INSERT in... if(alarm5 == 2) alarm5 = 3 strcpy(yylval.yystring,yytext) return IN into... strcpy(yylval.yystring,yytext) return INTO is... if(alarm4 == 1) alarm4 = 2 strcpy(yylval.yystring,yytext) return IS like strcpy(yylval.yystring,yytext) return LIKE module named strcpy(yylval.yystring,yytext) return NAMED open_cursor... signal3 = 0 strcpy(yylval.yystring,yytext) return OPEN_CURSOR open strcpy(yylval.yystring,yytext) return OPEN or strcpy(yylval.yystring,yytext) return OR order strcpy(yylval.yystring,yytext) return ORDER_BY update strcpy(yylval.yystring,yytext) return UPDATE procedure... signal3 = 1 strcpy(yylval.yystring,yytext) return PROCEDURE record alarm4 = 1 strcpy(yylval.yystring,yytext) return RECORD schema_db select... strcpy(yylval.yystring,yytext) return SELECT set strcpy(yylval.yystring,yytext) return SET status strcpy(yylval.yystring,yytext) return STATUS use strcpy(yylval.yystring,yytext) return USE VALUES strcpy(yylval.yystring,yytext) return VALUES where strcpy(yylval.yystring,yytext) return WHERE with strcpy(yylval.yystring,yytext) with_counter++ return WITH ID strcpy(yylval.yystring,yytext)... if(alarm5 == 3) save_input_type (3) if(alarm4 == 3) save_input_type(2) if(alarm == 1) save_variables_type() if(signal3 == 1) save_proc_name()... return ID. return yytext[0] /* returnera enskilt tecken */ %% /* slut på regeldelen */ /* C- kods del. OBS! Här visas yywrap() och save_proc_name() */ /* Flera funktioner visas i bilags delen längsta bak i rapporten,*/ /* alla funktioner i flex redovisas inte */ /**********************************************************************************/ /* YYWRAP */ /**********************************************************************************/ /* A function that is used when END OF FILE is found */ /**********************************************************************************/ yywrap() return (1) /*************************************************************************************************/ /* save_proc_name() fungerar så här: ( se gärna tidigare i rapporten då en *.sme - fil presenteras) */ /* Det som ska sparas är xxx : */ /* procedure xxx(yyy: in Dbif_DDD.yyy NOT NULL) */ /* Flaggan signal3 sätts till 1 när nyckelordet procedure förekommer sedan sparas yylval.yystring då xxx */ /* förekommer i ID och signal3 = 1. I funktionen där sparandet utförs så sätts signal3 = 0 för att */ /* undvika att sparande av korrupt data. */ * /* Nyckelordet procedure förekommer även i Cursor men då sätts alltid signal3 = 0 i efterföljande */ /* keyword så yylval.yystring inte sparas felaktigt. Name räknas upp efter kopieringen. */ /*Behovet att spara uppkommer då id ska genereras i *.adb på plats där xxx inte */ /* längre är aktuellt token. */ 15

/**********************************************************************************/ /* SAVE_PROC_NAME */ /**********************************************************************************/ /* A function that saves the procedures name from yylval.yystring used later */ /* when printing to *.adb */ /**********************************************************************************/ save_proc_name() fixstring(yylval.yystring) strcpy(procedure_name[name].input, yylval.yystring) name++ signal3 = 0 big.bison s struktur med förklarande kommentarer inom /*...*/ : /* Deklarations- del, C- kods del */ % #include <errno.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include "link.h" /*Här finns struct för länkad lista och struct-array*/ #define FILE_NAME 50 FILE *file /* Pekare till input filen dvs. *.sme */ char *tok /* Håller sträng som ska genereras i *.ads */ char *tok_adb /* Håller sträng som ska genereras i *.ads */ /* Strängkonstanter som används. OBS! Några har plockats bort*/... char *one = " " char *three = " " char *six = " " char *nine = " " char *twelve = " " char *fifteen = " " char *eighteen = " " char *fence = " ----------------------------------------------------\n" char *t_r_i = "type Row_Type is" char *s_ql = "Sqlcode : Sql_Standard.Sqlcode_Type" char *standard = "Sql_Standard.Indicator_Type" char *if_not = "if not ((Sqlcode < 0) or (Sqlcode = 100)) then" char *raise = "raise Samedl_Standard.Null_Value_Error" /* Variabeldeklarationer OBS! Några har plockats bort */... extern int lineno /*keeps track on actual line in input file*/ extern int with_counter /*keeps track on with occurrences*/ extern int signal3 /* flags used in big.flex, but is re- defined in main */... extern int alarm5 extern int cu2 /* index used in big.flex, but is re- defined in main */... extern int sqllen... extern struct inp_curs database_stmnt[200]... extern struct inp_curs curs_variables_type[200] int ready = 0 /* Används då with- blocken genereras */ int first = 0 /* Används då if- else block genereras i *.adb*/ % /* Bison del */ %union /* yylval omdefinieras till att enbart hålla strängar*/ char yystring[100] /* type deklareras. (Dvs. lablar eller icketerminaler) */ %type <yystring> cur_like aoo_id aoo_id1 aoo_id2 aoo_orderby aoo_and aoo_token %type <yystring> cur_i4 cur_tok1 cur_s cur_tok2 aoo_status2 %type <yystring> prog the_end with abstract abs_id record rec_id rec_is 16

%type <yystring> rec_token rec_end the_cursor cur_id3 cur_id4 cur_token1 %type <yystring> the_procedure p_procedure1 p_tkn p_tkn1 p_id p_null p_is1 %type <yystring> select sel_id sel_tkn sel_nam sel_null sel_into sel_from %type <yystring> sel_status update u_id u_set u_tkn u_tkn1 u_where delete %type <yystring> del_from del_id del_where del_status insert ins_id ins_tkn %type <yystring> ins_tkn ins_into end_param ins_from values ins_status cur_afterid %type <yystring> cur_in cur_null cur_for cur_select cur_xnn cur_from cur_where cur_t %type <yystring> aoo_like1 aoo_or aoo_is1 aoo_tkn aoo_is aoo_proc1 aoo_proc aoo_oc1 %type <yystring> aoo_cursor aoo_is1 aoo_oc aoo_fe aoo_status aoo_status1 aoo_tkn1 %type <yystring> '' ':' '(' ')' ',' '<' '>' '=' '"' /* token deklareras. (Dvs. terminaler) */ %token <yystring> ABSTRACT ANDCLOSE_CURSOR CLOSE CURSOR DELETE END FETCH FOR %token <yystring> FROM GET GET_IS ID INSERT IN INTO IS LIKE NAMED N NN OPEN_CURSOR %token <yystring> OPEN OR ORDER_BY PROCEDURE RECORD SET SELECT STATUS UPDATE %token <yystring> USE VALUES WITH WHERE %% /* slut på deklarationsdel */ /* Grammatik del OBS! Grammatik delen är förkortad*/ /*... == aktiondelen borttagen,... == stycken av grammatik borttagen */ /* prog är start label för grammatiken */ /* Några funktioner som används i grammatikdelen, förklaras i C- kods */ /* delen längre fram i rapporten */ /* Olika with- block genereras för olika antal with förekomster som flex hittat*/ prog: WITH with if(with_counter == 1) gen_with(1) if((with_counter > 1) && (ready == 0)) gen_with(2) ready = 1 USE with ABSTRACT abstract... RECORD record... CURSOR the_cursor... PROCEDURE the_procedure... END the_end tok_adb = oneemit_adb(tok_adb) tok_adb = $1emit_adb(tok_adb) tok_adb = "\n"emit_adb(tok_adb) tok = oneemit_ads(tok) tok = $1emit_ads(tok) tok = "\n"emit_ads(tok) /*********** END************************************************************/ the_end: ID '' tok_adb = "\n\n\n" emit_adb(tok_adb) tok_adb = "" emit_adb(tok_adb) fixstring($1)tok_adb = $1 emit_adb(tok_adb) tok = "\n\n\n" emit_ads(tok) tok = "" emit_ads(tok) fixstring($1)tok = $1 emit_ads(tok) /************WITH---------USE***********************************************/ with: ID '' prog /************ ABSTRACT ************************************/ abstract: ID abs_id... abs_id: IS prog... /*************RECORD**************************************/... /********************************************************************************/ Några ytterligare bitar av grammatik delen visas i bilaga2. 17

%% /* C- kods del */ /*... == delar av funktion borttagen */ /* Här redovisas main(int argc, char** argv) och generate_databasecall() */ /* I bilaga2 redovisas fler bison funktioner, dock inte alla. */ I mainfunktionen startas parsningen genom answer = yyparse(). Under parsningen så kontrolleras först grammatikdelen. Då botten är nådd så utförs alla aktioner. Eftersom aktions börjar från botten och går uppåt, så blir den länkade listan bakvänd. Därför måste den vändas innan den skrivs ut i writeoutputfile_ads(). I lämpliga aktions så laddas tok = lämplig sträng. tok kan laddas med konstanta strängar, strängar, $- värden och värden struct- array sparade värden. tok är sedan inparameter i emit_ads(tok), där tok hamnar i den länkade listan. fixstring(char s[]), används vid behov för att stuva om i strängen links *endptr_ads /* End of linked list in *.ads */ links *startptr_ads /* Start of linked list in *.ads */ links *endptr_adb /* End of linked list in *.adb*/ links *startptr_adb /* Start of linked list in *.adb*/ FILE *fileads /* Pointer to output file *.ads */ FILE *fileadb /* Pointer to output file *.adb */ /*############################# MAIN ######################################*/ main(int argc, char** argv) extern FILE yyin /* yyin är flex inputfil */ int answer= -1 int index = 1 int len int output links *freeptr_ads links *freeptr_adb startptr_ads = NULL endptr_ads = NULL startptr_adb = NULL endptr_adb = NULL if(startptr_ads = (links *) malloc (sizeof (links)) ) startptr_ads->next = NULL strcpy(startptr_ads->strval,"") else printf("error creating linked list!!") exit(1) if(startptr_adb = (links *) malloc (sizeof (links)) ) startptr_adb->next = NULL strcpy(startptr_adb->strval,"") else printf("error creating linked list!!") exit(1) if(argc >= 1) do /* fler variabler re- definieras */ char outputads[file_name] char outputadb[file_name] startptr_ads = NULL startptr_adb = NULL memset(outputads, 0, FILE_NAME) memset(outputadb, 0, FILE_NAME) with_counter = 0 ready = 0 first = 0 cu2 = 0... 18

stm = 0 signal3 = -1... stmnt = - 1 file = fopen(argv[index],"r") if(!file) fprintf(stderr,"cant open argv %s\n", argv[index]) exit (1) yyin = file len = strlen(argv[index]) len = len - 3 strncpy(outputads, argv[index], len) strncpy(outputadb, argv[index], len) strncat(outputads, "ads", 3) strncat(outputadb, "adb", 3) fileads = fopen(outputads,"w") fileadb = fopen(outputadb,"w") if(!(fileads)!(fileadb) ) printf("could not open outputads: %s\n",strerror(errno)) exit(1) answer = yyparse() /* Start the parser */ if(answer == 0) /* 0 == Parse- Success */ if( (freeptr_ads = (links *) malloc (sizeof (links))) ) freeptr_ads = startptr_ads else fprintf(stderr,"no memory...") if( (freeptr_adb = (links *) malloc (sizeof (links))) ) freeptr_adb = startptr_adb else fprintf(stderr,"no memory...") writeoutputfile_ads() /* Write to file ads */ writeoutputfile_adb() /* Write to file adb */ fclose(fileads) fclose(fileadb) fclose(file) index++ /* increment for next *.sme */ while(freeptr_ads->next!= NULL) /* free memory */ startptr_ads = freeptr_ads freeptr_ads = freeptr_ads->next free(startptr_ads) while(freeptr_adb->next!= NULL) startptr_adb = freeptr_adb freeptr_adb = freeptr_adb->next free(startptr_adb) startptr_ads->next = NULL startptr_ads = NULL free(freeptr_ads) startptr_adb->next = NULL startptr_adb = NULL free(freeptr_adb) /* END answer if */ else fprintf(stderr,"\n error in parse\n") exit(1) 19

while(index < argc) /* END while */ /* END if */ return 0 /* Databas anropet som samlats av flex genereras */ /****************************************************************************/ /* GENERATE_DATABASECALL */ /****************************************************************************/ /* A function that generates the proper database call for */ /* dbif_c_i.adb */ /****************************************************************************/ generate_databasecall()... tok_adb = "\n"emit_adb(tok_adb) stm = stm -1 tok_adb = "end" emit_adb(tok_adb) tok_adb = nine emit_adb(tok_adb) tok_adb = "\n"emit_adb(tok_adb) tok_adb = " ), SQL_NTS)"emit_adb(tok_adb) tok_adb = rec_name2[rec2].inputemit_adb(tok_adb) tok_adb = " & Local_Log_" emit_adb(tok_adb) tok_adb = "\"" emit_adb(tok_adb) tok_adb = "=" emit_adb(tok_adb) tok_adb = database_stmnt[stm].input /*databas anrop*/ emit_adb(tok_adb) tok_adb = "\"" emit_adb(tok_adb) tok_adb = "Sts := SqlPrepare(Stmt, To_C (" emit_adb(tok_adb) tok_adb = twelve emit_adb(tok_adb) tok_adb = "\n"emit_adb(tok_adb)... 20

Ada till ODBC lösning För att utvärdera om det vara möjligt att från ADA anropa ett ODBC interface som sen anropar en sybase databas letades det fram en freeware produkt. Freeware eller open source produkten bestod av en ODBC driver manager (iodbc) och ett ODBC bibliotek från OpenLink. Efter att ha löst vissa problem vid testningen så fungerade det, vilket resulterade i att företaget (CELSIUS) bestämde att en kommersiell produkt skulle inhandlas. Orsaken till att Celsius ville ha en kommersiell produkt var att det oftast saknas support och uppdateringar till freeware produkter och man ville försäkra sig om att detta skulle finnas. En produkt från företaget MERANT beställdes hem DataDirect Connect ODBC 3.6. Denna produkt visade sig vara något svår att konfigurera, men efter en del testande gick det att få fart på förbindelsen mellan databasen och Ada genom ODBC gränssnittet. Nästa steg var att för hand generera en koppling mellan Ada och ODBC för den nya produkten. Detta gjordes för att få fram en mall att gå efter vid genereringen av koden med hjälp av kompilatorsystemet. Mallen byggdes med hjälp av material hämtat från nätet, och med hjälp av ODBC exemplet ovan. Här följer den handskrivna mallen: Alla för Celsius specifika namn på variabler, filnamn osv. har ersatts. -- ************************************************************** -- Generated Abstract Body for: -- Module: DBIF_XXX -- Source: dbif_xxx.sme -- Date : 2000 Jun 08 14:04:35 -- ************************************************************** -- With är ungefär som include i C with Dbif_Odbc_Support use Dbif_Odbc_Support with Ois_Basic_Types use Ois_Basic_Types with Ada.Text_IO use Ada.Text_IO with Ada.Command_Line use Ada.Command_Line with Interfaces.C use Interfaces.C with Iodbc use Iodbc package body Dbif_XXX is use Sql_Standard -- Procedur för att hämta ett filnamn. -- Inparameter är filnamnet utparameter är status på hur det gick. procedure Get_Filename (Filename_Log : in Dbif_ZZZ.Beteck_Not_Null Row : in out Get_Filename_Type_Row Stats : out Dbif_ZZZ.Query_Stats) is -- Lokala variabler Local_Filename : Sql_Standard.Char(1.. 40 + 1) Sqlcode : Sql_Standard.Sqlcode_Type Cols : aliased SQLreturn Env : aliased SQLHENV Dbc : aliased SQLHDBC Stmt : aliased SQLHSTMT Num : aliased Sqlsmallint Text : String (1..100) Sts : Retcode Text_Length : aliased SDWORD Sql_Error : exception Command_Syntax_Error : exception -- Error hantering procedure Error (Sts : Retcode Text : String) is Sqlstate : aliased char_array (0..10) 21

Errmsg : aliased char_array (0..400) Nativerr : aliased SQLINTEGER Actmsglen : aliased SQLSMALLINT Ret : Retcode Begin -- Om inte lyckat resultat, skriv ut felmeddelande -- och res ett undantag if sts /= Sql_Success and Sts /= SQL_SUCCESS_WITH_INFO then Ret := SQLError(Env, Dbc, Stmt, Sqlstate, Nativerr'Access, Errmsg, Iodbc.SQL_MAX_MESSAGE_LENGTH, Actmsglen'Access) if Ret = Iodbc.Sql_Error then Put_Line("SQLError call failed") raise SQL_ERROR end if Put ("Return code = ") Put_Line(SQLRETURN'Image(Ret)) Put_Line("From = " & Text) -- Detailed SQL error if Ret /= SQL_NO_DATA_FOUND then Put_Line("SQLSTATE = " & String(Interfaces.C.To_Ada(Sqlstate))) Put_Line("NATIVE ERROR = " & SQLINTEGER'Image(Nativerr)) Put("MSG = ") for Ix in 1.. Size_T(ActMsgLen) loop Put(Character(ErrMsg(Ix))) end loop raise Sql_Error end if raise Sql_Error end if end Error -- Start av programmets main del begin -- Kontrollera antal argument till programmet if Argument_Count /= 3 then Put_Line ("syntax: datasourcename username password ") raise Command_Syntax_Error end if -- fyll variabler med blanksteg för att slippa skräptecken Row.Filename := (others => ' ') Local_Filename := (others => ' ') -- Sts är handtaget till en intern ODBC struktur som innehåller all information om -- ODBC s environment Sts := SqlAllocEnv (Env'Unchecked_Access) Error (Sts, "allocenv") -- Alloc Connect Sts := SqlAllocConnect (Env, Dbc'Unchecked_Access) Error (Sts, "allocdbc") -- Connect Sts := SQLConnect (Dbc, Error (Sts, "connect") -- Prepare a statement for execution and -- bind output fields to program variables To_C(Argument (1)), Argument (1)'Length, To_C(Argument (2)), Argument (2)'Length, To_C(Argument (3)), Argument (3)'Length) Sts := SqlAllocStmt (Dbc, Stmt'Unchecked_Access) Error (Sts, "allocstmt") -- prepare sql statement to be executed 22

declare Local_Filename_Log constant String := "'" & Stripp_Trailing_Blanks(String(Filename_Log)) & "'" begin Sts := SqlPrepare (Stmt, To_C ("select YYY.filnamn from YYY where YYY.YYY_id = " & Local_Filename_Log), SQL_NTS) end Error (Sts, "prepare") -- Bind columns Sts := SqlBindCol (Stmt, 1, Sql_Char, Local_Filename'Address, Local_Filename'Length,Text_Length'Unchecked_Access) Error (Sts, "bindcol text 1") -- Execute the statement to get a result set Sts := SqlExecute (Stmt) Error (Sts, "execute") -- Check if execute returned any columns. -- Needed after fetch for error handling Cols := SQLNumresultCols(Stmt,Num'access ) -- Fetch result to column Sts := Sqlfetch (Stmt) Error (sts, "FETCH" & Retcode'Image (sts) ) -- Release resources and drop connection Sts := SQLFreeStmt (stmt, SQL_DROP) Error (Sts, "freestmt") Sts := SQLDisconnect (dbc) Error (Sts, "disconnect") Sts := SQLFreeConnect (dbc) Error (Sts, "freeconect") Sts := SQLFreeEnv (env) Error (Sts, "freeenv") Status := Dbif_Odbc_Support.Get_Stats (Sts) if not ((sts < 0) or (sts = 100)) then -- if error in sqlnumresultcols call if Cols /= 0 then raise Samedl_Standard.Null_Value_Error else -- if no columns in result if integer(num) <= 0 then raise Samedl_Standard.Null_Value_Error else Row.Filename := ( Dbif_ZZZ.Filnamn_Not_Null ( Local_Filename (1.. Local_Filename'Last - 1)) ) end if end if end if end Get_Filename ---------------------------------------------------------------- end Dbif_XXX Det som var det stora problemet vid själva byggandet av mallen var att Adas hårt typade språk krävde ombyggnationer. Ada kräver att längden, storleken på i stort sett allt är känt vid kompilering. På grund av detta var det tvunget att alla variabler fylldes med blanktecken eftersom man då i anropande applikation kan plocka bort alla blanksteg från höger tills man hittar något tecken som är skilt från blanktecken. Genom att göra så kan man vara säker på att det man får tillbaks bara innehåller resultatet av SQL uttrycket och inget annat. Tack vare den lösningen så kunde man jobba med inparametrar av olika längd så länge man i den lokala funktionen alltid skapade variabler av samma längd och typ som inparametrarna. Detsamma gäller när man ska returnera resultatet av en SQL fråga till den anropande applikationen. 23

För att kunna testa om den handskriva mallen fungerade krävdes ett testprogram som skickar in inparametrar och kontrollerar resultatet. Testprogrammet behövs eftersom den Ada kod som innehåller kopplingen till ODBC och databasen samt utför själva SQL frågan och returnerar svaret ligger i ett Ada paket (package). Ada paket kan inte exekveras rakt upp och ner, utan behöver precis som i C ett main program. Utifrån mallen gjordes försök till att generera ADA kod som fungerade mot ODBC gränssnittet. Detta gjordes mot en av de mindre SME filerna för att se om det gick, vi hann dock inte göra det för någon större SME fil då tiden blev knapp. Men I princip skulle det gå att göra för alla SME filer troligtvis, eftersom uppbyggnaden och syntaxen är ungefär den samma I alla SME filer. 24

Resultat Examensarbetet visar att det går att genom ett kompilatorförfarande med *.sme fil som input och Dbif_DDD.sme samt S_db.sme som hjälpfiler generera Ada- kod, inklusive Ada- kod som anropar ODBC- gränsytan. Framtida arbete Fortsatt arbete skulle innefatta färdigställande av kompilatorsystemet så att det kan hantera alla *.sme filer mer generellt. Förbättra kontrollen av syntax och semantik i kompilatorsystemet samt lägga till felhantering, vilket till viss del saknas i vår lösning. En analys av prestanda, stabilitet, flexibilitet och kompabilitet mellan de olika systemen borde göras. Analysen skulle ligga som underlag för ett beslut om att byta ut nuvarande system mot vårt nya kompilatorsystem. 25

Litteraturförteckning Brown, D, Levine, J, Mason, T, (1992), lex & yacc, O Reilly, USA Cohen N.H., (1996), Ada as a second language, McGraw-Hill, USA Self, J, Ayacc User s Manual Taback D, Deepak Tolani, Aflex- An Ada Lexical Analyzer http://www.combo.org/flex/manpage.html http://www.combo.org/bison/manpage.html http://www.openlinksw.com/ http://www.iodbc.org/index.htm http://www.unixodbc.com/ 26

Bilaga1 Flex och bison introduktion Här kommer en kort flex- och bison introduktion. Flex och bison är gnu- versioner av lex och yacc. Därför tar exemplen nedanför även upp lex och yacc. Version som använts: gnu.bison-1.25.0.0.exe och gnu.flex-2.5.4.0.exe Token = variabler, nyckelord, enskilda tecken osv. Ett mönster (pattern) som definierats i flex specifikationen. %%- tecknen är avskiljare mellan de olika sektionerna i flex och även i bison. Flex Flex är ett verktyg som genererar en scanner ( eller en lexikal analysator). Scannern känner igen lexikala mönster i en inputfil. Flex läser en specifikationsfil, och får då beskrivningen på hur scannern ska genereras. Själva beskrivningen är uppbyggd av regler dvs. par av reguljära uttryck och en tillhörande aktionsdel i C- kod. Flex genererar en C- kods fil lex.yy.c, vilken definierar en rutin yylex() Denna fil kompileras och länkas, för att bli ett exekverbart program. När den exekverbara filen körs så analyserar den inputfilen, för att hitta reguljära uttryck, och när dessa hittats så utförs aktion som hör till. Specifikationsfilen till flex består av tre sektioner: definitioner %% regler %% C kod Definitionsdelen består av inkludering av bibliotek, definitioner och variabel deklarationer som används I C- kod delen. Det som förekommer mellan % och % kopieras ordagrant till yy.lex.c I regel delen så beskrivs vilka tokens som ska godkännas, och vilken aktion som ska utföras då just detta token påträffas, på denna form: token aktion. C- kods delen kopieras rakt av till yy.lex.c. Ett enkelt exempel av en enkel (och förenklad) flex specifikation: % /* nothing this time */ % %% [ \t] + /*definierar white space, dvs. en eller flera tabbar och mellanslag, anger ingen.*/ /* aktion, dvs. gör ingenting*/ did am are were have be printf( %s : är ett verb \n, yytext) /* yytext håller det aktuella token som behandlas*/ [ a-za-z] printf( %s : är inte ett verb \n, yytext) /* Inom klamrarna så anges sekvens av */ /* tecken som får förekomma*/ %% main 1

yylex() Om vi kompilerar och testar följande: did I have fun. Så blir resultatet: did : är ett verb I : är inte ett verb have : är ett verb fun : är inte ett verb Bison Bison producerar en parser (y.*.tab.c ) utifrån den grammatik som specificerats. Hur bison kan användas: 1. Skriv en grammatik på en form som bison förstår. För varje grammatisk regel i språket så definiera en aktion som ska utföras då just denna regel påträffas. 2. Skriv en lexikal analysator som kan processa inputfilen och som passar ( returnerar) påträffade tokens till bison- parsern. 3. Skriv en main funktion som anropar den Bison- producerade parsern. 4. Hantera fel som kan uppstå. Specifikationsfilen till bison består av tre sektioner: % C- deklarationer % Bison deklarationer %% grammatik %% C- kod I C- deklarationens delen kan makros definieras, diverse nödvändiga #include xxx, typer och variabler deklareras. Bison deklarationsdelen deklarerar tex. terminal och icke- terminal- symboler, beskriver ev. operatorprioritet, och det semantiska värdet av olika symboler. Bison och flex tillhandahåller diverse symboler som kan användas eller omdefinieras. Exempel på detta: yylval : en variabel där yylex() kan placera det semantiska värdet som är associerat med ett token. Kan endast hålla ett heltalsvärde men detta går att omdefiniera med hjälp av union som beskrivs längre ner. yyerror() :felhanterare som yyparse() kallar på vid upptäckta fel yylex() :funktion som returnerar ett nytt token till parsern yyparse() :startar parsern yyin : hantag till inputfil. Parsern kallar på yyin t.o.m. END OF FILE yywrap() : då yylex() når END OF FILE så anropas denna funktion. Om yywrap() returnerar 0 så är det inte slut på input, om returvärdet är 1 så avslutas parsningen %type :anger icketerminaler %token :anger de tokens ( terminaler) som används %union : här kan yylval omdefinieras %% :separerar de olika sektionerna i både flex och bison /* */ :kommentarer : :separerar label (icketerminal) från regeln :avslutar en regel :separerar alternativa regler från samma icketerminal 2

Exempel på lex och yacc filer som samverkar lex, med kommentarer /* definitionsdel: */ % #include <stdio.h> #include "y.tab.h" /* Inkludering av parserns.h- fil */ int c /* Variabel deklaration* / extern int yylval /* yylval finns deklarerad yacc*/ void evaluate () /*Funktion som används av lex */ int temp=0 /* som omvandlar yytext, en sträng- array* / int i /* till ett heltal som är kompatibelt*/ for (i=0 i < yylengi++) c=yytext[i] temp= temp*10+c-'0' yylval= temp /* med yylval, som hanterar just heltal*/ % delim [ \t] /*Tecken inom klamrarna anger vilka tecken räknas */ /* till delim (mellanslag och tabb) */ WS delim+ /*WS består av delim, en eller fler*/ DIGIT [0-9] /*Digit består av sekvensen från 0 till 9*/ /* regel del:*/ %% WS /* Vid WS, dvs. upprepade delims, == gör inget*/ DIGIT+ evaluate() /*Vid digits evaluera o returnera */ return (VALUE) /* sedan VALUE till parsern */ [^0-9ws] c = yytext[0] /*Tecken som ej är digit*/ return(c) /returneras som de ä*/ /* ex. + eller - */ /*C- kods del*/ %% yywrap() return(1) yacc, med kommentarer yacc arbetar sig först ner (börjar i exemplet nedan, vid mini (som är start label)i grammatikdelen, och kontrollerar att grammatiken stämmer. När bison nått botten i grammatikdelen så utförs aktions samtidigt som parsern arbetar sig uppåt och avslutar i aktion som hör till label mini. Denna traverserings ordning kallas bottomup. /*deklarations del*/ % #include <stdio.h> % %token VALUE /*är ett heltals värde*/ %start mini /*grammatik del med ev. aktions*/ %% mini : mini line'\n' mini'\n' 3

line : expr printf("%d\n",$1) expr : expr '+' term $$=$1+$3 term term : term '*' factor $$=$1*$3 factor factor : '('expr')' $$ = $2 VALUE /*C- kods del*/ %% main() printf ("Programmet har startat\n\n") return (yyparse()) /*startar parsning*/ yyerror(s) /*felhanterare*/ char *s printf ("%s\n",s) Klarläggande av uttryck som används I yacc: expr : expr '+' term $$=$1+$3 expr (= $$) : expr (= $1) + (= $2) term (= $3) $1 och $2 plockas ner från parser- stacken för att processas och sedan passas uppåt genom att läggas tillbaka på stacken i $$. I detta fall så adderas värdet av $1 och $3, detta resultat läggs i $$. Värdet av $$ passas uppåt, hamnar i $1 vid regeln ovanför och kan som i detta exempel skrivas ut: printf("%d\n",$1). 4

Bilaga2 En *.sme fils uppbyggnad OBS! Exemplet är en förenkling av en *.sme fil skriven i SAMeDL notation. Alla för Celsius specifika namn på variabler, filnamn osv. har ersatts -------------------------------------------------------------- xxx, iii,... är variabler uppbyggda på formen: börjar med minst en gemen följs av siffror, gemen, versal samt tecknet _. XXX.xxx är variabler uppbyggda på formen börjar med en sträng av versaler tom., som sedan följs av siffror, gemener, versal samt tecknet _.. avvänds som separator /* Filen börjar med en kort informations del som är bortkommenterad med -- */ -- -- UNIT NAME dbif_xxx -- -- KEYWORDS --... -- -- CONTENTS -- -- Revision History: -- -- Dependencies: --... --============================================================== /* Filen med variablernas egenskaper*/ with Dbif_DDD /* Filen med tabellernas egenskaper*/ abstract module dbif_xxx is authorization S_db /* En record hänger ihop med en procedure. Dessa två funktioner */ /* samverkar för att ta ut en viss post ur en tabell. */ record xxx is yyy: dbif_ddd.xxx NOT NULL /* Här visas vilken typ av post*/ end xxx /* som ska hämtas dbif_ddd.xxx NOT NULL */ /* läggs i variabeln yyy. */ ----------------------------------------------------------------- procedure xxx(xxx: in Dbif_DDD.xxx NOT NULL) /*input är en sök variabel: */ /* kan Tex. ange vilken specifik anläggnings- telefonnummer som efterfrågas */ is select yyy NOT NULL /* yyy är vilket id, tas från record*/ into : xxx /* Var resultatet ska läggas */ from XXX /* I vilken tabell variabeln finns */ where XXX.xxx = xxx /* Sök- villkor som ska uppfyllas */ status Dbif_DDD.xxx /* I en *.sme fil kan godtyckligt många par av record och procedure förekomma */ /* En Cursor hämtar flera poster från en tabell, inparametern anger sök- villkoret */ Cursor xxx(yyy: in Dbif_DDD.xxx NOT NULL) for select xxx NOT NULL, /* Anger poster som ska hämtas*/ iii, jjj from XXX /* Anger från vilken tabell */ where XXX.xxx = yyy /* Sökvillkor */ order by xxx /* Hur resultatet ska organiseras */ is /* Procedurer som öppnar och stänger Cursor */ 1