Stavolta tenteremo di fare in VB qualcosa di un po' più complesso di DAO, ovvero parserizzare e compilare dati, quante volte avete usato OCX non adatti al vostro caso specifico per tale uso?
Questo poichè scrivere un Parser in VB è un uso del linguaggio raro, visto che tutti i compilatori e gli IDE sono scritti in C++ o anche C
Operazioni di I/O
Iniziamo col chiarire che parserizzare e compilare non sono attività separate dallÆI/O dei dati, ma dipendenti dal successo di queste
Poiché
Dim Stringa$
Open "codicesorgente.c" For Input As 1
Do Until Eof(1) : Line Input#1, Stringa$ : Compile(Stringa$): Loop
Close 1
Public Sub Compile(Source$)
Dim Src$
Do Until Tokens(Source$)=0
Src$=GetToken(Tokens(Source$))
If IsKeyWord(Src$) Then ....
If IsIdentifier(Src$) Then...
Loop
End Sub
Questo codice non è che un semplice esempio di I/O e parserizzazione
Esaminiamola
Public Sub Compile(Source$)
Dim Src$
1->Do Until Tokens(Source$)=0
2->Src$=GetToken(Tokens(Source$))
3->If IsKeyWord(Src$) Then ....
4->If IsIdentifier(Src$) Then...
Loop
End Sub
Primi elementi di parserizzazione: I token
CosÆè un token?
Esso è un elemento di una linea di codice sorgente, non dipendente da altri adiacenti per la formazione del suo significato generale, ma che può avere bisogno di altri elementi adiacenti per la formazione del suo significato specifico
Ovvero?
Dim X As Integer
Dim
X
As
Integer
sono i 4 token
Ciascuno di essi è un token poichè il suo significato generale ci è chiaro a priori
Dim->dichiarazione di variabili
X->identificatore
As->parola chiave di tipo
Integer->tipo di dati
Insieme i quattro token formano una espressione
Una espressione è un insieme di token che abbiano un significato nella sintassi S del linguaggio L
Ovvero che E appartenga allÆinsieme S di L
Cioè
Dim KX 2E+456 As If IsLong()
EÆ un insieme di 6 token, ma non è una espressione
Poichè la sintassi S di Vb stabilisce che
Dim id As tipo
E la sintassi di id è tale che
IsId=True if id like [0-Z] and mid(id,1,1) like [A-Z]
Ovvero può contenere sia numeri che caratteri, ma deve iniziare con un carattere
Questo ci introduce ad un primo uso delle regole sui token e sulle espressioni
Ma quale token?....
Ricordate che in base allÆelemento da parserizzazare P la sintassi S usata può usare 2 o più identificativi I
Ovvero alla ricerca di XYZ in un file di testo esistono 2 tipi di token
Il secondo tipo di token potrebbe anche essere detto "ogni altra sequenza", poichè un token è una sequenza di caratteri
Tornando al nostro file osserviamo che
P=file.txt
S=XYZ, ognialtracosa
I=parolachiave, idestranei
Ovvero per P la sintassi S in collaborazione con gli identificativi I definisce come
parolachiave-XYZ
idestranei-ognialtracosa
Tale sintassi è molto facile, ma ovviamente ne esistono altre molto più difficili, quale quella di VB(ma essa è molto semplice rispetto a quella di C++)
AllÆinterno di una generica sintassi S si potrebbe osservare lÆesistenza di 2 tipi di espressioni
LÆespressione totale è tale che essa contiene almeno 1 token per ogni tipo di token consentito dalla sintassi usata per la sua generazione
LÆespressione nulla invece è quella che contiene 1 solo token, di solito INVIO (che è un token poichè ha un significato generale(di fine della linea) ed uno specifico(uguale a quello generale))
EÆ abbastanza facile capire che esistono poi le espressioni normali, la maggioranza che contengono dei token, di uno o più tipi
Ricordate se conoscete C++/C che lÆespressione nulla non è lÆistruzione nulla
Poichè
;
la prima linea è lÆespressione nulla(1 token di newline), la seconda è lÆistruzione nulla(2 token, uno di punteggiatura è uno di newline)
Tornando a Vb, possiamo dire che una vera e propria espressione nulla esiste, ma non è applicabile in tutti i contesti, e neanche Vb dispone di una vera istruzione nulla, almeno in tutti i contesti, poichè
If X=True Then ...
dopo il Then non è possibile omettere codice, ma noi possiamo crearne una
Tip per VB5
Per creare lÆistruzione nulla aprite un nuovo form
Scrivete tale codice
Sub IstruzioneNulla()
End Sub
salvatelo come Template, ed ecco il vostro form
If X=True Then IstruzioneNulla
Dopo tanta teoria...mi sarò pure meritato un file da parserizzare?
In effetti, si, sono stato molto teorico allÆinizio dellÆarticolo, ma adesso passiamo a noi, diciamo di avere un generico file F di nome "miofile.ml"(ml sta per miolinguaggio)
Dobbiamo parserizzarlo per ottenere miofile.bas, la sintassi S è la seguente
Sintassi S per il file F
Sintassi per il token T |
Tipo di Token di T e descrizione di esso |
Token VBT per VB |
Set x=y |
Parola chiave con 2 parametri, un identificatore e un numero |
Let x=y |
Message x,y,z |
Parola chiave con 3 parametri, 2 stringhe ed un numero |
MsgBox x,z,y |
BailOut |
Parola chiave senza parametri |
End |
TempBailOut |
Parola chiave senza parametri |
Stop |
Print x |
Parola chiave con 1 parametro, una stringa |
Print x |
SymbolNew x,y |
Parola chiave con 2 parametri, due identificatori |
Dim x as y |
TellMeWhat x,y |
Parola chiave con 2 parametri, una stringa ed un identificatore |
y=InputBox(x) |
La sintassi è Case Sensitive
Questa è la sintassi S di L(Linguaggio) applicata ad F(file)
Inizialmente notiamo che esistono i seguenti tipi di token
Un identificatore è un nome di variabile
Una parola chiave è un token che non può essere usato come identificatore
Un numero è un qualsiasi token che può essere usato in ambito matematico
Una stringa è una sequenza di caratteri delimitata da " e "
Adesso possiamo iniziare a scrivere il codice
Saltiamo gli ovvi preliminari di I/O che già vi dovrebbero essere noti per passare al dunque
Siamo sicuri che non sia una stringa?
Il modo migliore per parserizzare?
Quello context-depending, ovvero per trovare XYZ nel nostro esempio precedente conviene una semplice Instr(), e se dobbiamo trovarla come parola singola su una linea un Len() sarà adatto al nostro scopo, ma per compilare Linux non abbiamo scelta, dovremo districarci tra decine di tipi di token ed adattamenti di S(Sintassi) al fine di ottenere qualcosa che sia accettabile(non dico veloce)
e che non sbagli a compilare
if (a==5) {
A=4;
}
assegnando ad a il valore 4, per cui ripassiamo i due tipi di sintassi
Ovvero, VB e Delphi sono linguaggi per cui
If
if
iF
sono equivalenti, in C++ e Java invece
class
Class
claSS
clasS
sono diversi, solo il primo class è una parola chiave, gli altri sono identificatori validi
Tornando alla nostra sintassi S iniziamo a scrivere il codice C
Un po' di stinghe, qualche parola chiave ed il .EXE è fatto
Prima cosa ci servono il file di Input ed il file di Output, i loro handle saranno 1 e 2
Poi ci serve una stringa per memorizzare i dati
Le fasi della parserizzazione di un token |
|
|
|
|
Fase 1.GetTokenType()
La funzione GetTokenType(Token$) stabilisce il tipo di token, chiamando una funzione per ogni tipo di token, la cui convenzione di chiamata è Istipotoken(per esempio IsIdentifier)
Public Function GetTokenType%(Token$)
If IsKeyWord(Token$) Then
GetTokenType%=TKN_KEYWORD
Exit Function
ElseIf IsIdentifier(Token$) Then
GetTokenType%=TKN_IDENTIFIER
Exit Function
ElseIf IsNumber(Token$) Then
GetTokenType%=TKN_NUMBER
Exit Function
ElseIf IsString(Token$) Then
GetTokenType%=TKN_STRING
Exit Function
Else
GetTokenType%=TKN_NONE
Exit Function
End If
End Function
Le costanti TKN_* sono numeri interi così definiti
Const TKN_KEYWORD=1
Const TKN_IDENTIFIER=2
Const TKN_NUMBER=3
Const TKN_STRING=4
Const TKN_NONE=-1
Questo per chiarezza, poichè TKN_STRING è più chiaro di 4
Il caso TKN_NONE è possibile?
Si:
ADGB
non è alcun token del linguaggio, ne è stato definito prima da SymbolNew
Adesso, le singole funzioni di verifica sono abbastanza facili, tranne IsIdentifier()
Comunque iniziamo
Public Function IsString(Token$) As Boolean
IsString=(Left(Token$,1)="æ" And Right(Token$,1)="æ")
End Function
Public Function IsKeyWord(Token$) As Boolean
Select Case Token$
Case "SymbolNew","TellMeWhat","Set","BailOut","TempBailOut","Message","Print"
IsKeyWord=True
Case Else
IsKeyWord=False
End Select
End Function
Public Function IsNumber(Token$) As Boolean
IsNumber=IsNumeric(Token$)
End Function
La prossima volta scopriremo come scrivere IsIdentifier()
Ciao a tutti!!!
Stavolta tenteremo di fare in VB qualcosa di un po' più complesso di DAO, ovvero parserizzare e compilare dati, quante volte avete usato OCX non adatti al vostro caso specifico per tale uso?
Questo poichè scrivere un Parser in VB è un uso del linguaggio raro, visto che tutti i compilatori e gli IDE sono scritti in C++ o anche C
Operazioni di I/O
Iniziamo col chiarire che parserizzare e compilare non sono attività separate dallÆI/O dei dati, ma dipendenti dal successo di queste
Poiché
Dim Stringa$
Open "codicesorgente.c" For Input As 1
Do Until Eof(1) : Line Input#1, Stringa$ : Compile(Stringa$): Loop
Close 1
Public Sub Compile(Source$)
Dim Src$
Do Until Tokens(Source$)=0
Src$=GetToken(Tokens(Source$))
If IsKeyWord(Src$) Then ....
If IsIdentifier(Src$) Then...
Loop
End Sub
Questo codice non è che un semplice esempio di I/O e parserizzazione
Esaminiamola
Public Sub Compile(Source$)
Dim Src$
1->Do Until Tokens(Source$)=0
2->Src$=GetToken(Tokens(Source$))
3->If IsKeyWord(Src$) Then ....
4->If IsIdentifier(Src$) Then...
Loop
End Sub
Primi elementi di parserizzazione: I token
CosÆè un token?
Esso è un elemento di una linea di codice sorgente, non dipendente da altri adiacenti per la formazione del suo significato generale, ma che può avere bisogno di altri elementi adiacenti per la formazione del suo significato specifico
Ovvero?
Dim X As Integer
Dim
X
As
Integer
sono i 4 token
Ciascuno di essi è un token poichè il suo significato generale ci è chiaro a priori
Dim->dichiarazione di variabili
X->identificatore
As->parola chiave di tipo
Integer->tipo di dati
Insieme i quattro token formano una espressione
Una espressione è un insieme di token che abbiano un significato nella sintassi S del linguaggio L
Ovvero che E appartenga allÆinsieme S di L
Cioè
Dim KX 2E+456 As If IsLong()
EÆ un insieme di 6 token, ma non è una espressione
Poichè la sintassi S di Vb stabilisce che
Dim id As tipo
E la sintassi di id è tale che
IsId=True if id like [0-Z] and mid(id,1,1) like [A-Z]
Ovvero può contenere sia numeri che caratteri, ma deve iniziare con un carattere
Questo ci introduce ad un primo uso delle regole sui token e sulle espressioni
Ma quale token?....
Ricordate che in base allÆelemento da parserizzazare P la sintassi S usata può usare 2 o più identificativi I
Ovvero alla ricerca di XYZ in un file di testo esistono 2 tipi di token
Il secondo tipo di token potrebbe anche essere detto "ogni altra sequenza", poichè un token è una sequenza di caratteri
Tornando al nostro file osserviamo che
P=file.txt
S=XYZ, ognialtracosa
I=parolachiave, idestranei
Ovvero per P la sintassi S in collaborazione con gli identificativi I definisce come
parolachiave-XYZ
idestranei-ognialtracosa
Tale sintassi è molto facile, ma ovviamente ne esistono altre molto più difficili, quale quella di VB(ma essa è molto semplice rispetto a quella di C++)
AllÆinterno di una generica sintassi S si potrebbe osservare lÆesistenza di 2 tipi di espressioni
LÆespressione totale è tale che essa contiene almeno 1 token per ogni tipo di token consentito dalla sintassi usata per la sua generazione
LÆespressione nulla invece è quella che contiene 1 solo token, di solito INVIO (che è un token poichè ha un significato generale(di fine della linea) ed uno specifico(uguale a quello generale))
EÆ abbastanza facile capire che esistono poi le espressioni normali, la maggioranza che contengono dei token, di uno o più tipi
Ricordate se conoscete C++/C che lÆespressione nulla non è lÆistruzione nulla
Poichè
;
la prima linea è lÆespressione nulla(1 token di newline), la seconda è lÆistruzione nulla(2 token, uno di punteggiatura è uno di newline)
Tornando a Vb, possiamo dire che una vera e propria espressione nulla esiste, ma non è applicabile in tutti i contesti, e neanche Vb dispone di una vera istruzione nulla, almeno in tutti i contesti, poichè
If X=True Then ...
dopo il Then non è possibile omettere codice, ma noi possiamo crearne una
Tip per VB5
Per creare lÆistruzione nulla aprite un nuovo form
Scrivete tale codice
Sub IstruzioneNulla()
End Sub
salvatelo come Template, ed ecco il vostro form
If X=True Then IstruzioneNulla
Dopo tanta teoria...mi sarò pure meritato un file da parserizzare?
In effetti, si, sono stato molto teorico allÆinizio dellÆarticolo, ma adesso passiamo a noi, diciamo di avere un generico file F di nome "miofile.ml"(ml sta per miolinguaggio)
Dobbiamo parserizzarlo per ottenere miofile.bas, la sintassi S è la seguente
Sintassi S per il file F
Sintassi per il token T |
Tipo di Token di T e descrizione di esso |
Token VBT per VB |
Set x=y |
Parola chiave con 2 parametri, un identificatore e un numero |
Let x=y |
Message x,y,z |
Parola chiave con 3 parametri, 2 stringhe ed un numero |
MsgBox x,z,y |
BailOut |
Parola chiave senza parametri |
End |
TempBailOut |
Parola chiave senza parametri |
Stop |
Print x |
Parola chiave con 1 parametro, una stringa |
Print x |
SymbolNew x,y |
Parola chiave con 2 parametri, due identificatori |
Dim x as y |
TellMeWhat x,y |
Parola chiave con 2 parametri, una stringa ed un identificatore |
y=InputBox(x) |
La sintassi è Case Sensitive
Questa è la sintassi S di L(Linguaggio) applicata ad F(file)
Inizialmente notiamo che esistono i seguenti tipi di token
Un identificatore è un nome di variabile
Una parola chiave è un token che non può essere usato come identificatore
Un numero è un qualsiasi token che può essere usato in ambito matematico
Una stringa è una sequenza di caratteri delimitata da " e "
Adesso possiamo iniziare a scrivere il codice
Saltiamo gli ovvi preliminari di I/O che già vi dovrebbero essere noti per passare al dunque
Siamo sicuri che non sia una stringa?
Il modo migliore per parserizzare?
Quello context-depending, ovvero per trovare XYZ nel nostro esempio precedente conviene una semplice Instr(), e se dobbiamo trovarla come parola singola su una linea un Len() sarà adatto al nostro scopo, ma per compilare Linux non abbiamo scelta, dovremo districarci tra decine di tipi di token ed adattamenti di S(Sintassi) al fine di ottenere qualcosa che sia accettabile(non dico veloce)
e che non sbagli a compilare
if (a==5) {
A=4;
}
assegnando ad a il valore 4, per cui ripassiamo i due tipi di sintassi
Ovvero, VB e Delphi sono linguaggi per cui
If
if
iF
sono equivalenti, in C++ e Java invece
class
Class
claSS
clasS
sono diversi, solo il primo class è una parola chiave, gli altri sono identificatori validi
Tornando alla nostra sintassi S iniziamo a scrivere il codice C
Un po' di stinghe, qualche parola chiave ed il .EXE è fatto
Prima cosa ci servono il file di Input ed il file di Output, i loro handle saranno 1 e 2
Poi ci serve una stringa per memorizzare i dati
Le fasi della parserizzazione di un token |
|
|
|
|
Fase 1.GetTokenType()
La funzione GetTokenType(Token$) stabilisce il tipo di token, chiamando una funzione per ogni tipo di token, la cui convenzione di chiamata è Istipotoken(per esempio IsIdentifier)
Public Function GetTokenType%(Token$)
If IsKeyWord(Token$) Then
GetTokenType%=TKN_KEYWORD
Exit Function
ElseIf IsIdentifier(Token$) Then
GetTokenType%=TKN_IDENTIFIER
Exit Function
ElseIf IsNumber(Token$) Then
GetTokenType%=TKN_NUMBER
Exit Function
ElseIf IsString(Token$) Then
GetTokenType%=TKN_STRING
Exit Function
Else
GetTokenType%=TKN_NONE
Exit Function
End If
End Function
Le costanti TKN_* sono numeri interi così definiti
Const TKN_KEYWORD=1
Const TKN_IDENTIFIER=2
Const TKN_NUMBER=3
Const TKN_STRING=4
Const TKN_NONE=-1
Questo per chiarezza, poichè TKN_STRING è più chiaro di 4
Il caso TKN_NONE è possibile?
Si:
ADGB
non è alcun token del linguaggio, ne è stato definito prima da SymbolNew
Adesso, le singole funzioni di verifica sono abbastanza facili, tranne IsIdentifier()
Comunque iniziamo
Public Function IsString(Token$) As Boolean
IsString=(Left(Token$,1)="æ" And Right(Token$,1)="æ")
End Function
Public Function IsKeyWord(Token$) As Boolean
Select Case Token$
Case "SymbolNew","TellMeWhat","Set","BailOut","TempBailOut","Message","Print"
IsKeyWord=True
Case Else
IsKeyWord=False
End Select
End Function
Public Function IsNumber(Token$) As Boolean
IsNumber=IsNumeric(Token$)
End Function
La prossima volta scopriremo come scrivere IsIdentifier()
Ciao a tutti!!!