PB Interpreter

Anwendungen, Tools, Userlibs und anderes nützliches.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Ah, jetzt wird's mir klar.
Stimmt, auch nach deinem Schema kann man das ganze Zeug einmal kompilieren und es immer wieder aufrufen, je nachdem, wie man an die Sache herangeht.
Klar interessiert das den User nicht, aber für den Entwickler ist's umso interessanter, denn endlich kann der Laie auch komplexere Sachen in seiner Lieblingssprache machen, statt eine neue Sprache lernen zu müssen.

Bin mal auf dein Ergebnis gespannt. :allright:
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Mal so nebenbei...

Zeile 95

Code: Alles auswählen

Define source$, exe$=GetTemporaryDirectory()+"pb-executable_"+RemoveString(script_filename$, "/")
Erzeugt unter Windows einen Fehler, da ich ja den Pfad zu PB mit einem Doppelpunkt angeben muss was ein nicht erlaubtes Sonderzeichen für Dateinamen ist.... Das muss unbedingt noch gefiltert werden über ein RemoveString(script_filename$, ":")

Nur um den Fehler mal aufgezeigt zu haben.

Zudem wäre es besser die Ausgabe des Programms mit folgendem Code zu formatieren:

Code: Alles auswählen

Procedure.s nl2br(string.s)
  string = ReplaceString(string, #CRLF$, "<br />")
  string = ReplaceString(string, #LF$, "<br />")
  ProcedureReturn ReplaceString(string, #CR$, "<br />")
EndProcedure

;[...]

;Zeile 136 bei mir
If Not compiler
		error("Compiler could not be started." + "<br />" + "Pfad: " + GetPathPart(ProgramFilename())+"compilers/pbcompiler")
	EndIf

Zeilennummern können leicht vom Orginal abweichen =)


EDIT:
Trotz der anpassungen bekomme ich folgenden Fehler:

Code: Alles auswählen

Compilation process did not finish correctly. Error: 

******************************************
PureBasic 4.30 (Windows - x86)
******************************************

Compiling C:\WINDOWS\pb-executable_Cxampphtdocspbtesttest.pb.pb
Loading external libraries...
Starting compilation...
4 lines processed.
Creating executable.

- Feel the ..PuRe.. Power -
Hier noch meine Testdatei

Code: Alles auswählen

#!C:/xampp/purebasic/interpreter.exe -w 
OpenConsole() 
PrintN("Content-Type: text/html"+#LF$) 
Print("Hallo Welt!") 
EDIT2:
Zudem wäre es besser den Programmierer das Temporäre Verzechniss selber bestimmen zu lassen... Damit man auch eine bessere struktur hat, wenn man später größere Projekte baut so alla

Code: Alles auswählen

Seite
     -> source
          ->templates
               -> index.tpl
          -> index.pb
     -> compiled
          -> index
Allgemein könnte man eine kleine Einstellungsschnittstelle bauen, das immer einen config.xml oder config.ini gesucht wird... oder per Parameter ein Pfad zu diesereinen übergeben werden kann... Weiste wie ich meine?

EDIT3:
Okay... Habs gemerkt... /quiet statt --quiet

EDIT4:
Jetzt bekomm ich aber ein

Code: Alles auswählen

Serverfehler!
Die Anfrage kann nicht beantwortet werden, da im Server ein interner Fehler aufgetreten ist. 

Fehlermeldung: 
Premature end of script headers: test.pb 

Sofern Sie dies für eine Fehlfunktion des Servers halten, informieren Sie bitte den Webmaster hierüber. 

Error 500
192.168.0.160
08.06.2009 20:12:13
Apache/2.2.8 (Win32) DAV/2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_autoindex_color PHP/5.2.5 mod_perl/2.0.3 Perl/v5.8.8 
vom Apache zugeworfen und in den Logs steht auch nicht mehr :-\
Jemand ne Ahnung?


EDIT5:
Hab den Fehler gefunden... Es ist der Fix, für Linux:

Code: Alles auswählen

; circumvent a bug in ProgramRunning() (this command always returns 1),
		; see http://www.purebasic.fr/english/viewtopic.php?t=37273
		If ProgramExitCode(program) <> -1 : Break : EndIf
kommentiert man es aus, finktioniert es einwandfrei.

MFG
Blackskyliner
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Hab die erste Beta des Template Parser fertig =)
Es werden noch keine Fehler abgefangen, da ich erstmal gerne wissen möchte, ob ich irgendwo etwas "dirty" programmiert hab. Bitte dann aber auch mit entsprechenden Verbesserungsvorschlägen.

Ich Poste den Code hier, da er ja meines erachtens nach unmittelbar etwas mit der Sache zu tun hat. Bei Bedarf kann auch von mir oder einem Mod, der das dann halt abspaltet, in einen eignen Beitrag geschrieben werden.

Hier der SoruceCode:

Code: Alles auswählen

; Copyright: Blackskyliner, 2009
; E-Mail: blackskyliner@gmx.de
; This is a simple template parser which is able to 
; parse every given file to PrintN() function calls.
; It also can replace some variable and function placeholder
; The last one, the function placeholder are executed and then
; the return value will be written inside the PrintN()


EnableExplicit


; Just a little helper function for developer
Procedure.s nl2br(string.s)
  string = ReplaceString(string, #CRLF$, "<br />")
  string = ReplaceString(string, #LF$, "<br />")
  ProcedureReturn ReplaceString(string, #CR$, "<br />")
EndProcedure

; Sorry but i couldn't think of another name....
Structure replaceStruct
	search.s
	replace.s
EndStructure

Structure functionStruct
	search.s
	*replace.i ;x64 compatible
EndStructure

Enumeration 
	#Compare
EndEnumeration

#LDELIM$ = "<<"
#RDELIM$ = ">>"

Procedure.s parseTemplate(file.s, List replacer.replaceStruct(), List callableFunctions.functionStruct())
	Define.s currentLine, output, currentVar
	Define.i foundExpressions = 0, k
	Dim expressions.s(0)
	
	If ReadFile(0, file)
		If CreateRegularExpression(#Compare, #LDELIM$+"(.*)"+#RDELIM$) = 0
			ProcedureReturn "Internal Error[Compare_Init_parseTemplate]: " + RegularExpressionError()
		EndIf
	
		While Eof(0) = 0
			currentLine = ReadString(0)
			
			
			If MatchRegularExpression(#Compare, currentLine)
				foundExpressions = ExtractRegularExpression(#Compare, currentLine, expressions())
				
				For k = 0 To foundExpressions-1
					;Debug Mid(expressions(k), 1, 2 + Len(#LDELIM$))
					If Mid(expressions(k), 1, 2 + Len(#LDELIM$)) = #LDELIM$+"f:"
						;proccess functions
						currentVar = Mid(expressions(k), 3 + Len(#LDELIM$), Len(expressions(k))- (2 + Len(#LDELIM$) + Len(#RDELIM$)))
						
						Debug "Function: " + currentVar

						ResetList(callableFunctions())
						ForEach callableFunctions()
							If callableFunctions()\search = currentVar
								;call function and fill the function placeholder with the return data
								If callableFunctions()\replace <> #Null
									currentLine = ReplaceString(currentLine, expressions(k), PeekS(CallFunctionFast(callableFunctions()\replace))) 
								EndIf
							EndIf
						Next
					Else
						;proccess variables
						currentVar = Mid(expressions(k), 1 + Len(#LDELIM$), Len(expressions(k)) - (Len(#LDELIM$) + Len(#RDELIM$)))
						
						Debug "Variable: " + currentVar
						
						ResetList(replacer())
						ForEach replacer()
							If replacer()\search = currentVar
								currentLine = ReplaceString(currentLine, expressions(k), replacer()\replace)
							EndIf
						Next
					EndIf
					
					
				Next
			EndIf
			
			
			output = output + "PrintN("+#DQUOTE$+currentLine+#DQUOTE$+")"+#CRLF$
		Wend
		
		FreeRegularExpression(#Compare)
		
		CloseFile(0)
	Else
		output = "File " + file + " not found."
	EndIf

	ProcedureReturn output
EndProcedure

Procedure.s cleanPlaceholder(out.s)
	Define.i foundExpressions = 0, k
	Dim expressions.s(0)
	
	If CreateRegularExpression(#Compare, #LDELIM$+"(.*)"+#RDELIM$) = 0
		ProcedureReturn "Internal Error[Compare_Init_cleanPlaceholder_1]: " + RegularExpressionError()
	EndIf
	
	
	
	If MatchRegularExpression(#Compare, out)
		foundExpressions = ExtractRegularExpression(#Compare, out, expressions())
		
		For k = 0 To foundExpressions-1
			out = ReplaceString(out, expressions(k), "")
		Next
	EndIf
	
	FreeRegularExpression(#Compare)
	
	; all empty PrintN are filtered out here...
	; Maybe buggy because I only kill the TAB's
	If CreateRegularExpression(#Compare, "PrintN\("+#DQUOTE$+"(\t*)"+#DQUOTE$+"\)") = 0
		ProcedureReturn "Internal Error[Compare_Init_cleanPlaceholder_2]: " + RegularExpressionError()
	EndIf
	
	If MatchRegularExpression(#Compare, out)
		foundExpressions = ExtractRegularExpression(#Compare, out, expressions())
		
		For k = 0 To foundExpressions-1
			out = ReplaceString(out, expressions(k), "")
		Next
	EndIf
	
	
	FreeRegularExpression(#Compare)
	
	ProcedureReturn out
EndProcedure


; -- Test

; Procedure.s test_function()
; 	ProcedureReturn "Hallo aus einer Funktion!"
; EndProcedure
; 
; NewList r.replaceStruct()
; NewList f.functionStruct()
; 
; AddElement(r())
; r()\search = "festVar"
; r()\replace = "Hallo Welt aus einem Replacer"
; 
; AddElement(f())
; f()\search = "testFunc"
; f()\replace = @test_function()
; 
; 
; OpenConsole()
; 
; Print(cleanPlaceholder(parseTemplate("C:\test.tpl",r(),f())))
; 
; Input()

; test.tpl
; 
; <html>
; <head>
; 	<title>Parser Test</title>
; </head>
; 
; <body>
; 	Hallo Welt aus einem Template!<br/>
; 	<<f:testFunc>>
; 	<<f:testFunc2>>
; 	<<festVar>>
; 	<<f:testFunc3>>
; 	<<f:testFunc4>>
; </body>
; </html>
Wenn die RegEx Funktionen stören, wegen der Lizenz, könnte ich diese durch gleiche, aber dafür langsamere PB-Native Stringoperationen austauschen...

Viel Spaß erstmal damit, beim Testen :)
Der Parser muss in den Interpreter integriert werden... mal sehn wie ich das Regele... aber Ihr könnt ja erstmal einige Templates wie ihr sie euch vorstellt testen... Ob ihr Fehler findet.

EDIT:
Mir fällt grade ein Designfehler auf, der dann beim intergrieren in den Interpreter ein Problem wird... Ich werd das zwar alles nochmal um eine ganze Ecke verändern, aber immerhin kann ja am jetzigen Gedankengut ja sicherlich jemand was lernen ^.^


MFG
Blackskyliner
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Uh, da haste aber reingehauen... :lol:
Dann wollen wir mal:


> da ich ja den Pfad zu PB mit einem Doppelpunkt angeben muss
Ahh, beim 3. Mal überlegen, weiß ich endlich, was du meinst. Ja das ist korrekt. Der komplette Pfad inklusive Dateiname wird ja als Dateiname genommen und enthält unter Windows daher auch einen Doppelpunkt. Gut mitgedacht! Normalerweise denke ich an sowas aber bei diesem Projekt muss ich mich voll und ganz auf Linux konzentrieren, weil Lunix/Unix eben Neuland für mich ist.
Gut, ändere das einfach, eine Änderung wird ja sowieso nötig, weil du ja den Frontslash / durch einen Backslash \ ersetzen musst.
Danke für den Hinweis!

> Zudem wäre es besser die Ausgabe des Programms mit folgendem Code zu formatieren
Du meinst, die Ausgabe des Interpreters, falls ein Fehler auftritt?
Das brauchst du nicht. Ändere in der Prozedur error() den Content-Type von "text/html" nach "text/plain". Das veranlasst den Browser den Text so wie er ist auszugeben, ohne Formatierung. Auch HTML-Tags werden dann ignoriert. Das funzt in meinem IE8 aber nicht immer, deswegen habe ich text/html dringelassen. Wenn's geht, würde ich sofort auf text/plain umsteigen, in jedem Fall.

> Trotz der anpassungen bekomme ich folgenden Fehler
Hier stößt du auf einen Bug in PureBasic, der noch nicht behoben wurde. Unter Linux funktioniert ProgramRunning() nicht richtig, unter Linux sieht es so aus, als würde das Program ewig weiterlaufen. Daher habe ich es auskommentiert.
Siehe ungefähr zeile 140. Unter Windows müsste der Befehl funktionieren, habs mal getestet gehabt. Der Vorgang soll in Zeile 140 dann abgebrochen werden, wenn eine der folgenden Bedingungen wahr ist:
  • Es liegt Kompileroutput vor.
    Beachte den Parameter --quiet auf Linux bzw. /quiet auf Windows. Er sorgt dafür, dass der Kompiler kein Output ausgibt, es sei denn es gibt einen Fehler (Syntaxfehler, Include nicht gefunden, etc.). Mit anderen Worten: Ist der Output gleich null, dann lief alles glatt. Da deine Fehlermeldung aber aussagt, der Vorgang sei erfolgreich abgelaufen, scheint mir das ein Hinweis darauf, dass du den Parameter /quiet vergessen hast. Dein Testprogramm ist nämlich einwandfrei.
  • FileSize(exe$) = -1
    Wenn die Exe-Datei nicht erstellt bzw. gefunden wurde
  • Wenn ein Timeout-Wert von 5 Sekunden erreicht wurde (ein Vorschlag von mir, finde deinen eigenen optimalen Wert!)
    Eine Internetseite, durch PureBasic generiert, die länger als 5 Sekunden braucht, ist vermutlich ein Fehlschlag. Also lieber vorsichtshalber abbrechen. Ist aber eine Idee von mir, kann jeder so handhaben, wie er es möchte.
  • Wenn der Kompiler immer noch läuft
    Sollte der Kompiler immer noch laufen, obwohl im Extremfall 5 Sekunden gewartet wurde, dann ist das Timeout erreicht.
> das immer einen config.xml oder config.ini gesucht wird
Das war das erste Problem, mit dem ich mit auseinandersetzen musste. Nehme ich eine config-XML? nein, dachte ich, zu viel Overhead. Eine INI-Datei? Nicht schlecht.
Aber der einzige Grund, warum ich mich letzendlich gegen eine Config-INI entschieden habe, war die Performance. Überleg mal, wenn 10 Leute deine Seite gleichzeitig aufrufen, bedeutet das, dass 10 Interpreter-Prozesse laufen, die alle auf 1 Datei zugreifen wollen. elbst, wenn alle nur lesen kann ich mir nur vorstellen, dass die Performance darunter leidet.
Ich war sehr froh, als ich es geschafft habe, alle Einstellungen schon im Sourcecode verankern zu können.

Ich rate dir, wenn du deinen eigenen temporären Pfad nehmen möchtest, zu folgenden 2 Möglichkeiten, die ich in Betracht ziehe:
  • Wahl des Temp-Verzeichnisses als Parameter
    Beispiel:

    Code: Alles auswählen

    #!C:/xampp/purebasic/interpreter.exe -w -t "C:/Windows/Temp/"
    Es könnte zum Beispiel einen Parameter -t geben (t = temporär). Nach -t muss dann das temporäre Verzeichnis folgen (ggf. muss man den Pfad in Anführungszeichen setzen!).
  • Anpassen des Temp-Pfades im Sourcecode
    Ändere den Temp-Pfad im Sourcecode und kompiliere den Interpreter erneut. Speichere ihn z. B. unter "interpreter2.exe". Das nimmste dann auch mit in dein PB-Verzeichnis rein. So hast du interpreter.exe und interpreter2.exe, jedes mit anderem temp-Verzeichnis.
Ein Hinweis zu den Parametern: In Version 1.1 auf Linux wird der jeweils letzte Parameter nicht erkannt. Lauten die Parameter also "-w -f", wird -f nicht erkannt, weil ein #CRLF$ dranklebt (das #CRLF$ ist ein unvorhergesehenes Produkt, verursacht, weil Apache das Skript aufruft, als würde es den Interpreter per Eingabeaufforderung bedienen; bestätigt man dort einen Befehl mit RETURN, landet dieses RETURN (zumindest unter Linux) mit in der Parameter-Zeile). Ich habe bereits eine Version 1.2 des Interpreters, die das behebt. Hast du unter Windows die gleichen Erfahrungen gemacht?
Darüber hinaus, werden die Parameter hinter der Shebang-Zeile alle als ein Parameter an den PB Interpreter übergeben, das ist béi mir unter Linux so. "-f -c -w" kriege ich also als einen Parameter mit ProgramParameter(0) rein, deswegen muss ich die am Anfang manuell mit StringField() aufteilen. Ist das unter Windows auch so?


> Habs gemerkt... /quiet statt --quiet
Alles klar. Trotzdem lösche ich meinen müsahm getippten Absatz oben nicht :-P

> Hab den Fehler gefunden... Es ist der Fix, für Linux
Richtig. Den Fix hab ich mir ausgedacht, hab ich ja oben auch schon geschrieben, warum.

> Wenn die RegEx Funktionen stören, wegen der Lizenz, könnte ich diese durch gleiche, aber dafür langsamere PB-Native Stringoperationen austauschen
Du brauchst die Lizenz nicht einzubinden. Das musst du nur, wenn du deine Software öffentlich zugänglich gemacht wird. Da dein Parser aber (vermutlich) für immer und ewig nur auf deinem Webspace schlummert und dort seine Arbeit verrichtet, wird den wohl nie jemand runterladen. Ergo: Keine Lizenz erforderlich.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Bin für heute erstmal fertig. Es funktioniert alles soweit...
Hab viel in deinem Interpreter anpassen müssen, da eine enge Integration von nöten war. Dafür ist jetzt aber auch fast alles in den Templates möglich :)

Sogar Schleifen sollten theoretisch möglich sein.

Hier ist der DL-Link: http://em.q-soft.ch/591PB%20Interpreter ... Parser.rar


Freue mich über jede Kritik. Hoffe ich hab nichts wichtiges gelöscht @AND51 ;)

Zudem musst du das mal unter Linux testen, da ich derzeit keins zur Hand habe. müsste aber eigentlich auch dort funktionieren.

Kleines Summary was alles neu ist poste ich im Verlauf des Tages, jetzt käme da eh nur Müll raus :lol:

Viel Spaß damit und Gute nacht :lol:

Blackskyliner
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Update! Version 1.5

Version 1.2 (kleinere Reparaturen) und 1.3 (Multiline Syntax) wurden nicht veröffentlicht, sondern mit neuen Funktionen zu einem Update 1.5 zusammengefasst:

Hier eine kurze Beschreibung, in voller Länge gibts die im englischen Forum: http://www.purebasic.fr/english/viewtop ... 691#293691

  • Multiline Syntax erlaubt es nun, mehrzeiligen Code zu schreiben! Das ist besonders nützlich, um größere Textpassagen mit HTML-Code einzubauen! Es gibt 3 Modi: einen mit und einen ohne Newline-Ersetzung und einen Modi, der Code aus externen Dateien an die aktuelle Stelle einfügt.
    Hier eine knappe Demonstration des ersten Modus' mit Newline-Ersetzung:

    Code: Alles auswählen

    OpenConsole() 
    Print("<<multiline 
    <html> 
    <head> 
       <title>My Website</title> 
    </head> 
    <body> 
       This is HTML code 
    </body> 
    </html> 
    <<")
    Wird vom Interpreter wie folgt umgewandelt:
    Ergebnis hat geschrieben:OpenConsole()
    Print("<html>"+#LF$+"<head>"+#LF$+" <title>My Website</title>"+#LF$+"</head>"+#LF$+"<body>"+#LF$+" This is HTML code"+#LF$+"</body>"+#LF$+"</html>")
  • Alle Parameter -c, -p, -w, -f jetzt auch in Langform (--compress, --parse, --warn, --force)
  • Neue Umgebungsvariablen wie PB_Interpreter_Version und PB_Interpreter_QueryStrings (Anzahl der GET-Variablen, siehe nächsten Punkt)
  • GET-Variablen werden vom Interpreter automatisch als Umgebungsvariablen bereitgestellt. Beim Aufruf der Seite www.and51.de/index.pb?name=Paul&Alter=23 stellt der Interpreter diese Umgebungsvariablen bereit:
    GET_name = Paul
    GET_Alter = 23
    Diese können ganz easy mit GetEnvironmentVariable() abgefragt werden
  • Seit Version 1.2 werden die übergebenen Programmparameter (-c, -f, usw.) korrekt erkannt. Vorher wurde der letzte Parameter immer verschluckt.

Eine ausführliche Beschreibung mit drei vollständigen Beispielen zur neuen Multiline-Syntax gibt's im englischen Forum (Link oben).
Fragen und Kommentare können natürlich weiterhin hier gepostet werden.
Der Downloadlink http://www.and51.de/pbinterpreter.zip ist natürlich weiterhin aktuell.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Stevie63
Beiträge: 86
Registriert: 06.05.2009 23:02
Computerausstattung: Win 10, i7, fsc celsius

Anregungen

Beitrag von Stevie63 »

Hallo!

Ich verfolge mit viel Interesse dein Projekt und wünsche Dir, daß deine Software auf breiter Linie zum Einsatz kommt!

Ich habe noch ein paar Anregungen:

1.) Du benutzt Print bzw. PrintN für die Ausgabe. Dies könnte evtl. bei nicht ASCII-basierten Texten zu Problemen führen (hast du das mal ausgetestet). Da könnte vielleicht WriteConsoleData weiterführen.
2.) Vervollständige deinen HTML-Output soweit, daß deine Seiten valide sind (zum testen: http://validator.w3c.org).
3.) Ich würde an deiner Stelle den html-output über die xml-library generieren. Ich hatte vor einiger Zeit ein bisschen damit herumexperimentiert, geht alles ganz gut. Ich schicke dir mal den code (ist "old and dirty", kann beliebig verändert werden)

Code: Alles auswählen

Procedure.s EncloseString (instring.s)
  ProcedureReturn Chr(34) + instring.s + Chr(34)
EndProcedure

Procedure.s HTML_DocType(doctype.s)

  dtype.s = ""
  If doctype.s = "XHTML 1.0"
    dtype + "<!DOCTYPE html PUBLIC " 
    dtype + EncloseString("-//W3C//DTD XHTML 1.0 Transitional//EN") + " "
    dtype + EncloseString("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd") + ">" + " "
 
  EndIf
  
  ProcedureReturn dtype.s
EndProcedure

Macro HTML_Initialize(xmldoc,xmlroot,xmlmain,doctype,html)
  xmldoc = CreateXML(#PB_Any,#PB_UTF8)
  xmlroot = RootXMLNode(xmldoc)
  xmlmain = MainXMLNode(xmldoc)

  doctype = CreateXMLNode(xmlroot,0,#PB_XML_DTD)
  SetXMLNodeText(doctype, HTML_DocType("XHTML 1.0"))

  html = CreateXMLNode(xmlroot,-1)
  SetXMLNodeName(html, "html")
  SetXMLAttribute(html, "xmlns", "http://www.w3.org/1999/xhtml")
  SetXMLAttribute(html, "xml:lang", "de")
EndMacro

Macro HTML_Head(head,html)
  head = CreateXMLNode(html,0)
  SetXMLNodeName(head, "head")
EndMacro

Macro HTML_Title(head,title,text="")
  title = CreateXMLNode(head,0)
  SetXMLNodeName(title,"title")
  SetXMLNodeText(title, text)
EndMacro

Macro HTML_Body(html,body,class="")
  body = CreateXMLNode(html,-1)
  SetXMLNodeName(body, "body")
  SetXMLAttribute(body, "class", class)
EndMacro

Macro HTML_Style(head,style)
  style = CreateXMLNode(head,-1)
  SetXMLNodeName(style,"style")
  SetXMLAttribute(style,"type","text/css")
EndMacro

Macro HTML_AddStyleClass(style,classname="",content="")
  dummy$ = GetXMLNodeText(style)
  SetXMLNodeText(style,dummy$+CRLF$+"."+classname+"{"+content+";}")
EndMacro

Macro HTML_AddStyle(style,elementname="",content="")
  dummy$ = GetXMLNodeText(style)
  SetXMLNodeText(style,dummy$+CRLF$+elementname+CRLF$+"{"+content+";}"+CRLF$)
EndMacro

Macro HTML_AddNode(parent,node,nodename,class="")
  node = CreateXMLNode(parent,-1)
  SetXMLNodeName(node,nodename)
  SetXMLAttribute(node,"class",class)
EndMacro
Eine Seite könnte dann folgendermaßen aussehen:

Code: Alles auswählen

  HTML_Initialize(xmldoc,*xmlroot,*xmlmain,*doctype,*html)
  HTML_Head(*head,*html)
  HTML_Title(*head,*title,"OSPS - Startseite")
  HTML_Body(*html,*body,"osp_body")
  HTML_Style(*head,*style)
  HTML_AddStyleClass(*style,"osp_body","font-family:Verdana; font-size:12px;background-color:#003333")
  HTML_AddStyleClass(*style,"osp_h1","font-size:18px;color:#ffffff;margin-bottom:0px")
  HTML_AddStyleClass(*style,"osp_h2","font-size:14px;color:#000000")
  HTML_AddStyleClass(*style,"osp_h3","font-size:14px;color:#000000")
  HTML_AddStyle(*style,"a:link, a:visited, a:active, a:hover","text-decoration:underline;font-weight:bold;color:#ffffff;font-size:12px")
  HTML_AddStyle(*style,"a:active, a:hover","color:#ff9200")
  HTML_AddStyle(*style,"a.menu:link, a.menu:visited","color:#ff9200")
  HTML_AddStyle(*style,"a.menu:active, a.menu:hover","color:#eeeeee")
  HTML_AddStyleClass(*style,"osp_title","padding-top:15px;height:24px")
  HTML_AddStyleClass(*style,"osp_menu","color:#ffffff;text-align:center;padding:10px 0px;border-top:1px solid #669999;clear:left")
  HTML_AddStyleClass(*style,"osp_menu","border:1px solid #ffffff;background-color:#669999;padding:5px;color:#ffffff")

  HTML_AddNode(*body,*p1,"p","osp_h1")
  SetXMLNodeText(*p1, "Diese Seite gibt es nicht.")  
  HTML_AddNode(*body,*p2,"p","osp_h2")
  SetXMLNodeText(*p2, "Wirklich nicht.")    
  
  Dim pp.l(100)
  
  For i=0 To 99
    HTML_AddNode(*body,pp(i),"p","osp_h3")
    SetXMLNodeText(pp(i), "Diese Seite gibt es nicht.") 
  Next i
  
  Dim pp.l(0)  
 



Auf die Console kannst du dann das xml mit ExportXML und PeekS raushauen.

Viele Grüße

Stevie
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Erst mal vielen Dank für deine aufmunternden Worte und für dein großes Interesse! :D

> Du benutzt Print bzw. PrintN für die Ausgabe. Dies könnte evtl. bei nicht ASCII-basierten Texten zu Problemen führen
Welche Ausgabe meinst du?
Die, wenn der Interpreter den Output des Programms an den Webserver (Apache) weitergibt? Der wird mit WriteConsoleData() ausgegeben, das ist klar. Das ist von Afang an so, denn schließlich soll ein Programm beliebige Inhalte generieren uns ausgeben können. Dazu zählen auch Binärdaten, wenn man zum Beispiel ein Bild generiert und daher Daten von MIME-Typ "image/*" ausgeben will.

Falls du die Stelle meinst, wo ich die Sourcedatei temporär erzeuge, zum anschließenden Kompilieren: Dort benutze ich WriteString() und ich schreibe automatisch korrekt im UTF-8, Unicode, oder ASCII Modus (da ich ggf. den BOM auslese).

Lediglich um Compilerfehler oder ähnliches anzuzeigen schalte ich anstelle des eigentlichen Ausgabe des Executables eine Fehlermeldung, die auf jeden Fall im Klartext ist, daher kann ich mir da das Print() erlauben.

Falls du die Code-Beispiele für die Executables meinst: Klar sollte man im Hinterkopf behalten, dass Print() vermutlich nicht für Binärdaten gemacht ist. WriteConsoleData() dürfte die bessere Wahl sein. Allerdings sind alle meine bisherigen Codebeispiele auf HTML bezogen und HTML ist ja nun mal Klartext.

Sag mir am besten nochmal, auf welche Stelle im Interpreter du dich beziehst.

> Vervollständige deinen HTML-Output soweit, daß deine Seiten valide sind
Nun, meine Example-Codes sollen nur demonstrieren, dass es funktioniert und wie es funktioniert. Der Benutzer soll die Möglichkeit haben und behalten, jegliche erdenklichen Output zu erzeugen und ausgeben zu können, also Texte, Bilder, Zip-Dateien, Musik... Also im Grunde ASCII- und Binärdaten. HTML-Code zu ergänzen, würde den Programmierer ein Stück weit in seiner Freiheit einschränken. Mein Interpreter macht keinerlei Vorgaben (das die erste Zeile kein PB-Code enthalten darf ist eine technische Einschränkung seitens des Webservers), sondern Apache macht eine Einschränkung: Das Executable muss bor dem eigentlichen Content den MIME-Typ plus Leerzeile ausgeben, Apache ergänzt den Header dann um alle nötigen HTTP-Angaben. Den Interpreter automatisch einen "text/html" Header setzen zu lassen, wenn der Programmierer diese Angabe weg lässt, wäre programmtechnisch mäßiger Aufwand, drückt aber dennoch auf die Performancebremse, denn alle nachfolgenden Daten müssten gepuffert werden. Dieser Aufwand, nur um die erste Zeile auf den ggf. vorhanden MIME-Typ zu checken, wäre es meiner Meinung nach nicht wert.

> Ich würde an deiner Stelle den html-output über die xml-library generieren
Das gilt auch nur für die Example-Codes. Wie jemand nun seinen HTML-Output generiert, bleibt natürlich jedem selbst überlassen. Grundsätzlich habe ich aber auch schon versucht, die XML-Lib dafür zu benutzen. Leider sind meine Versuche gescheitert, weil ich mich mit XML nicht so detailgenau auskenne, wie z. B. Kiffi. Dein Vorschlag über die XML-Lib zu gehen, hätte den Vorteil, dass der HTML-Code syntaktisch korrekt ist; da gebe ich dir Recht.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Stevie63
Beiträge: 86
Registriert: 06.05.2009 23:02
Computerausstattung: Win 10, i7, fsc celsius

Beitrag von Stevie63 »

Hallo,

danke für deine ausführliche Antwort. Ich hatte mich hauptsächlich auf die Bsp. mit Print und PrintN bezogen.

Ich bin gespannt, wies es mit deinem Projekt weitergeht. Vielleicht könntest du deine Erfahrungen ins Forum posten. Was mich besonders interessiert, wären z.B. Belastungstests.

Viele Grüße und weiterhin gutes Gelingen!

Stevie
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Danke!
Auch wenn es nicht wöchentlich Updates gibt, so ist und bleibt dieses Projekt dennoch aktiv. Schließlich betreue ich 2 ½ Homepages, die vorher mit Perl liefen, jetzt aber mit PureBasic.

Zum Thema Belastungstests kann ich dir nur eine grobe Diagnose geben.

Ich persönlich habe nur einen virtuellen Server, das heißt, ich teile mir einen echten Server mit 3 bis 5 anderen Kunden (je nach Anbieter unterschiedlich). Mir stehen maximal ca. 1,5 GHz und 384 MB RAM zur Verfügung. Es gibt keine Sound- oder Grafikkarte, daher würden die meisten Befehle aus der Sound Library und der 2D- bzw. 3D Library fehlschlagen (die Grafik wird iirc nur emuliert und taugt höchstensfür einfache Drawing-Sachen).

Jeder Seitenaufruf erzeugt eine neue Instanz des PB Interpreters. Das heißt, wenn 10 Leute gleichzeitig die Homepage aufrufen, ruft der Webserver Apache 10x den PB Interpreter auf. jede dieser Instanzen wiederum startet das Executable. Der enorme Vorteil ist ja, dass die Executables seit 1.1 standardmäßig nur dann kompiliert werden, wenn der Sourcecode neu ist oder die Exe noch nicht existiert. Alle weiteren Aufrufe laden nur die Exe, diese rattert ihre Print()-Befehle runter und gut ist.

Ein richtiger, sogenannter 'dedizierter', Server bewältigt natürlich ein größeres Pensum mit seinen großen Kapazitäten.
Die 3 wichtigsten Punkte zur Performancesteigerung sind (absteigend nach Relevanz sortiert):
  1. Den Modus -f bzw. --force nicht benutzen. Sonst wird die EXE bei jedem Aufruf neu erstellt, das kostet auf einem mittelmäßigem virtuellen Server wie meinem ca. 250 Millisekunden.
  2. Verwendung eines besseren Servers. Das Beste wäre ein dedizierter (eigenständiger) Server, aber die sind sehr teuer (ab ca. 60 €/Monat).
  3. Optimierung des Sourcecodes. Man sollte möglichst Delay() und sonstige, verzögernde Elemente aus seinem Code lassen, damit dieser den Content so schnell wie möglich generiert. Codeoptimierungen sind anzustreben.
Belastungstest, an die du denkst, habe ich bisher noch nicht durchgeführt. Ich habe nicht nachgeguckt, wie schnell ich PureBasic-Homepages aufrufen kann, ehe die Homepage in die Knie geht.
Ich gestehe auch, dass es auf meinem Server vorkommt, dass eine Seite mal nicht korrekt geladen wird. Das ist aber selten und meistens darauf zurückzuführen, dass ich meine Homepage direkt bearbeite (ich teste neu entwickelte Funktionen nicht in einer separaten Testumgebung, sondern direkt in der Homepage, was man eigentlich nicht machen sollte).
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Antworten