#import "Aprica.h"
// Aprica2
// copyright Pirmin Braun 1997-2009 - pirmin@pirmin.de
// all Rights reserved;
@implementation Application (Scripting2)
- (NSArray *)analyzeScriptNamed:(NSString *)s statements:(NSArray *)statements showErrors:(BOOL)showErrors;
{ // liefert ein Array von PBStatements;
LMA;
int errorCount = 0,i,j,i1,j1,i2,j2;
LMDN(nc); // namechecking; variableName->table
NSArray *nckeys;
int nest;
NSString *subname;
if(showErrors)LOG(([NSSWF @"########### analyzing Script named %@ ",s]));
for(i=0,j=[statements count];i<j;i++){ NSString *line = [statements oai:i];
PBStatement *stmt;
// preprocessor Anweisungen verarbeiten
stmt = [PBStatement statementFromLine:line];
if(stmt){ [stmt setSrclnr:i];
// drin lassen f. Fehlerlisting if([stmt opcode]==OPC_NOP)continue;
[lma addObject:stmt];
if([[stmt line]hasSecurePrefix:@"#eo "]){ [nc setSecureObject:[MYDD tableNamedCheap:[[stmt op2]content]] forKey:[[stmt op1]content]];
}
if(FILLED([stmt error]))errorCount++;
// -------------------- Nachbearbeitung multiline array --------------------------
if([stmt opcode]==OPC_Z_ml){ LMAN(mla);
i++;
while(i<j){ NSString *s1 = [statements oai:i];
if([s1 iE:@"\\end"]){ break;
}
[mla addObject:s1];
i++;
}
[stmt setOpcode:OPC_Z_set];
[[stmt operands]removeAllObjects];
[[stmt operands]addObject:[PBOperand operandWithConstantObject:mla]];
continue;
}
// -------------------- Nachbearbeitung Lookup --------------------------
if([stmt opcode]==OPC_lookupbegin){ // das dictionary aufbauen und in op2 stellen NSMutableDictionary *lud;
NSArray *colKeys=nil;
NSString *fs = @"\t";
int ckc = 0,ii,jj;
lud = [NSMutableDictionary dictionaryWithCapacity:10];
while(++i<j){ NSArray *a1,*a2;
NSMutableDictionary *rowDict;
NSString *s = [statements oai:i];
NSString *slc = [s lowercaseString];
if(!FILLED(s))continue; //Kommentarzeilen sind schon rausgefiltert
if([slc hasSecurePrefix:@"lookupend"])break;
if([slc hasSecurePrefix:@"lookupfs "]){ //custom fieldseparator NSString *s1 = [s substringFromIndex:9];
if(FILLED(s1))fs = s1;
continue;
}
if(!colKeys){ colKeys = [s componentsSeparatedByString:fs];
ckc = [colKeys count];
if(ckc <2){ [stmt setError:@" keine Spalten."];
}
continue;
}
a1 = [s componentsSeparatedByString:fs];
if([a1 count] < 2)continue; //Keine Zeilenwerte
a2 = [[a1 firstObject] componentsSeparatedByString:@","]; //schluesseliste; wenn nur ein schluessel auch ok
rowDict = [NSMutableDictionary dictionaryWithCapacity:10];
for(ii=1,jj=[a1 count];ii<jj && ii<ckc;ii++){ //anzahl colkeys kann unterschiedlich sein wie anzahl der zeilenwerte [rowDict setSecureObject:[a1 oai:ii] forKey:[colKeys oai:ii]];
}
for(ii=0,jj=[a2 count];ii<jj;ii++){ NSString *rowKey = [a2 oai:ii];
[lud setSecureObject:rowDict forKey:rowKey];
}
}
[stmt setOpcode:OPC_Z_set];
[stmt setTarget:[[stmt operands]firstObject]];
[stmt setTarget_ds:TGT_ds_vardict]; // intern
[[stmt operands]removeAllObjects];
[[stmt operands]addObject:[PBOperand operandWithConstantObject:lud]];
continue;
}
// -------------------- Nachbearbeitung Matrix --------------------------
if([stmt opcode]==OPC_matrixbegin){ // das Array aufbauen und in op2 stellen NSMutableArray *matrix;
NSString *fs = @"\t";
matrix = [NSMutableArray arrayWithCapacity:10];
while(++i<j){ NSArray *a1;
NSString *s = [statements oai:i];
NSString *slc = [s lowercaseString];
if(!FILLED(s))continue; //Kommentarzeilen sind schon rausgefiltert
if([slc hasSecurePrefix:@"matrixend"])break;
if([slc hasSecurePrefix:@"lookupfs "]){ //custom fieldseparator NSString *s1 = [s substringFromIndex:9];
if(FILLED(s1))fs = s1;
continue;
}
a1 = [s componentsSeparatedByString:fs];
[matrix addObject:a1];
}
[stmt setOpcode:OPC_Z_set];
[stmt setTarget:[[stmt operands]firstObject]];
[stmt setTarget_ds:TGT_ds_vardict]; // intern
[[stmt operands]removeAllObjects];
[[stmt operands]addObject:[PBOperand operandWithConstantObject:matrix]];
continue;
}
}
}
// namechecking
nckeys = [nc allKeys];
j1 = [nckeys count];
for(i=0,j=[lma count];i<j;i++){ PBStatement *stmt = [lma oai:i];
enum OPC opcode = [stmt opcode];
if(FILLED([stmt error]))continue; // hat schon einen Error
if(opcode == OPC_NOP)continue; // das #eo statement selbst
if(j1){ // ueberhaupt namechecking statements definiert NSString *tf = [stmt targetFull];
NSArray *ops = [stmt operands];
NSString *key1;
if(tf){ // target pruefen von Zuweisungsbefehlen for(i1=0;i1<j1;i1++){ NSString *nck = [nckeys oai:i1];
if([tf hasSecurePrefix:nck]){ key1 = [[tf componentsSeparatedByString:@"."]oai:1];
if([key1 rangeOfString:@"$"].length)continue; // variable keys koennen hier nicht geprueft werden
if(![[nc ofk:nck]plainAttrNamed:key1]){ [stmt setError:[NSSWF @"Namechecking: %@ %@",[[nc ofk:nck] dbName],key1]];
errorCount++;
}
}
}
}
// Operanden pruefen
for(i2=0,j2=[ops count];i2<j2;i2++){ NSString *opc = [(PBOperand *)[ops oai:i2]content]; // z.B. ($as.f1 + $as.rx.fy)
if(![opc isKindOfClass:[NSString class]])continue; // Matrix u. Lookup haben Dictionaries als Operanden drin
for(i1=0;i1<j1;i1++){ NSString *nck = [nckeys oai:i1]; // $as.
NSRange r = [opc rangeOfString:nck];
while(r.length){ int e=0;
opc = [opc secureSubstringFromIndex:r.location + r.length];
r = [opc rangeOfString:@"."];
if(r.length)e=r.location;
r = [opc rangeOfString:@" "];
if(r.length && (!e || (r.location < e)))e=r.location;
r = [opc rangeOfString:@")"];
if(r.length && (!e || (r.location < e)))e=r.location;
if(e){ key1 = [opc substringToIndex:e];
}else{ key1 = opc;
}
if(!([key1 rangeOfString:@"$"].length)){ // variable keys koennen hier nicht geprueft werden if(![[PBEO knownKeys]ofk:key1]){ if(![[nc ofk:nck]plainAttrNamed:key1]){ [stmt setError:[NSSWF @"Namechecking: %@ %@",[[nc ofk:nck] dbName],key1]];
errorCount++;
}
}
}
r = [opc rangeOfString:nck];
}
}
}
if(FILLED([stmt error]))continue; // hat schon einen Error
}
// jetzt noch verpointerung vornehmen; dabei koennen fehler dazukommen;
nest = 0;
[stmt setBranch:-1];
switch(opcode){ case OPC_gosub: // subroutinename constant;
subname = [[stmt op1]content];
i2=0;
for(;i2<j;i2++){ PBStatement *stmt_sub = [lma oai:i2];
int opc = [stmt_sub opcode];
if(opc==OPC_sub && [[[stmt_sub op1]content]iE:subname]){ [stmt setBranch:i2]; break;} }
break;
case OPC_sub:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_endsub){ if(!nest){ [stmt setBranch:i2]; break;} nest--;
}
if(opc==OPC_sub)nest++;
}
break;
case OPC_foreach:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_endfor){ if(!nest){ [stmt setBranch:i2]; break;} nest--;
}
if(opc==OPC_foreach)nest++;
}
break;
case OPC_continuefor:
i2=i-1;
for(;i2>=0;i2--){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_foreach){ if(!nest){ [stmt setBranch:i2]; break;}; nest--;
}
if(opc==OPC_endfor)nest++;
}
break;
case OPC_breakfor:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_endfor){ if(!nest){ [stmt setBranch:i2]; break;} nest--;
}
if(opc==OPC_foreach)nest++;
}
break;
case OPC_endfor:
i2=i-1;
for(;i2>=0;i2--){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_foreach){ if(!nest){ [stmt setBranch:i2]; break;}; nest--;
}
if(opc==OPC_endfor)nest++;
}
break;
case OPC_if:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if((opc==OPC_else || opc==OPC_endif) && !nest){ [stmt setBranch:i2]; break;} if(opc==OPC_endif)nest--;
if(opc==OPC_if)nest++;
}
break;
case OPC_else:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_endif){ if(!nest){ [stmt setBranch:i2]; break;} nest--;
}
if(opc==OPC_if)nest++;
}
break;
case OPC_while:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_endwhile){ if(!nest){ [stmt setBranch:i2]; break;} nest--;
}
if(opc==OPC_while)nest++;
}
break;
case OPC_continue:
i2=i-1;
for(;i2>=0;i2--){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_while){ if(!nest){ [stmt setBranch:i2]; break;}; nest--;
}
if(opc==OPC_endwhile)nest++;
}
break;
case OPC_break:
i2=i+1;
for(;i2<j;i2++){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_endwhile){ if(!nest){ [stmt setBranch:i2]; break;} nest--;
}
if(opc==OPC_while)nest++;
}
break;
case OPC_endwhile:
i2=i-1;
for(;i2>=0;i2--){ int opc = [[lma oai:i2] opcode];
if(opc==OPC_while){ if(!nest){ [stmt setBranch:i2]; break;}; nest--;
}
if(opc==OPC_endwhile)nest++;
}
break;
default:
[stmt setBranch:0]; // kein branch-Statement
break;
}
if([stmt branch]<0){ [stmt setError:@"nesting Error"];
errorCount++;
}
}
if(errorCount){ LMAN(listing);
NSString *sys,*err_summary;
int i,j;
err_summary = [NSSWF @"======== %@",s];
if(!showErrors){ LOG((err_summary));
[scriptErrors addObject:[NSSWF @"<a href=\"#\" onClick=\"{document.forms[0].script_clicked.value='%@'; document.forms[0].submitter.value='action_script_bu_open_script'; document.forms[0].submit();}\">======== %@</a>",s,s]]; }
for(i=0,j=[lma count];i<j;i++){ PBStatement *stmt = [lma oai:i];
if(showErrors){ if([stmt error]){ [listing addObject:[NSSWF @"%@ *** %@",[stmt line],[stmt error]]];
}else{ [listing addObject:[stmt line]];
}
}else{ if([stmt error]){ LOG([stmt description]);
[scriptErrors addObject:[stmt htmlDescription]];
}
}
}
if(showErrors){ NSString *fn = [NSSWF @"%@/%@.script",[_APP tempdir],[s replace:@"/" with:@"_"]];
// erzeugtes Listing oeffnen
[[listing componentsJoinedByString:@"\n"]WTF:fn];
sys = [NSSWF @"open \"%@\"",fn];
SYSTEM(sys);
}
}else{ if(showErrors)LOGI(([NSSWF @"Script %@ fehlerfrei",s]));
}
return lma;
}
- (void)analyzeScriptsIn:(NSDictionary *)d into:(NSMutableDictionary *)into;
{// alle Scripts analysieren
NSArray *ks = [d allKeys];
int i,j;
LOG(@"########### analyzing Scripts.");
for(i=0,j=[ks count];i<j;i++){ NSString *k = [ks oai:i];
NSArray *statements = [scriptDict ofk:k],*a;
a = [self analyzeScriptNamed:k statements:statements showErrors:NO];
[into setObject:a forKey:k];
}
LOG(@"########### finished analyzing Scripts.");
}
@end