Download upload.ee yandex
Use the command line:
7 "%FILE" %TEMPFILE"
Your source will open in a browser.
7=1+2+4
1 - save in %TEMP%, otherwise in the work folder of the utility.
2 - Launch the HTML file in the browser.
4 - do not add compiler settings at the end of the file
I had a problem using SyntaxHighlighting on Linux, so I wrote it myself. I haven't tested on Linux yet, but it should work.
Download: upload.ee, yandex
Even though I posted the source code, you still need to download the files. (style.css, KeyWordLst.lst, ProcedureLst.lst, ForSyntaxHighlighting.pb, Readme.txt)
Code: Select all
;- TOP
; AZJIO (2025.03.01)
EnableExplicit
#Char2 = SizeOf(Character)
;- ● #Constants
Enumeration
#SYNTAX_Text
#SYNTAX_Keyword
#SYNTAX_Comment
#SYNTAX_Constant
#SYNTAX_String
#SYNTAX_Function
#SYNTAX_Asm
#SYNTAX_Operator
#SYNTAX_Structure
#SYNTAX_Number
#SYNTAX_Pointer
#SYNTAX_Separator
#SYNTAX_Label
#SYNTAX_Module
#SYNTAX_CRLF
#SYNTAX_Space
#SYNTAX_Apostrophe
#SYNTAX_StringTilda
#SYNTAX_Bracket
#SYNTAX_MyFunc
#SYNTAX_Variable
#SYNTAX_SeparatorModule
#SYNTAX_FuncWinAPI
#SYNTAX_Unknown
EndEnumeration
XIncludeFile "ForSyntaxHighlighting.pb"
Structure Token
type.i
token.s
EndStructure
Procedure CodeParser(InputFile$, List token.Token())
Protected flgOpnQt, c, tilda
Protected id_file, Format, Text$, *c.Character
Protected LengthFile.q, indentNot, *start, *m
; MessageRequester("", InputFile$)
id_file = ReadFile(#PB_Any, InputFile$)
If Not IsFile(id_file)
MessageRequester("Error", "Error opening the source file" + #CRLF$ + #CRLF$ + InputFile$)
ProcedureReturn
EndIf
; LengthFile = Lof(id_file)
; *m0 = AllocateMemory(LengthFile + 2, #PB_Memory_NoClear) ; the buffer is allocated by the length of the file, since the code can be written in one line
; the loop is taken from deleting comments, so there is no line capture and pointer memorization.
; Mod1 = Instead of deleting the comment, we run through the loop to the end of the line
If id_file
Format = ReadStringFormat(id_file)
While Not Eof(id_file)
Text$ = ReadString(id_file, Format) ; we read line by line, so it's easier to analyze
indentNot = 0
; Debug "|" + Text$ + "|" ; we checked that the line is readable without #CRLF$
; Debug Text$
Text$ = RTrimChar(Text$, #TAB$ + " ") ; we remove the voids at the end of the line
*m = AllocateMemory(StringByteLength(Text$) + 400)
PokeS(*m, Text$)
*c = *m
; *c = @Text$
; flgSemicolon = 0 ; reset the flag
While *c\c
Select *c\c
;- !
Case '!' ; if ASM code, then stupidly skip this line (quoted lines in ASM as pseudocode)
; ReadSource = 1
If indentNot ; if the logical sign is "Exclusive OR"
AddElement(token())
token()\type = #SYNTAX_Operator
token()\token = "!"
Else ; if at the beginning of the line
AddElement(token())
token()\type = #SYNTAX_Asm
token()\token = PeekS(*c)
Break ; jump out to read the next line
EndIf
;- '
Case 39 ; ' ' apostrophe
indentNot = 1
*start = *c ; memorize the position
*c + #Char2
If *c\c = 0
Break
ElseIf *c\c = 39
AddElement(token())
token()\type = #SYNTAX_Apostrophe
token()\token = "''"
*c + #Char2
Continue
EndIf
Repeat
*c + #Char2
Until *c\c = 0 Or *c\c = 39 ; go to the end of the line or to the ending apostrophe
AddElement(token())
token()\type = #SYNTAX_Apostrophe
token()\token = PeekS(*start, (*c - *start) / 2 + 1)
If *c\c = 0
Break ; jump out if the end lines or apostrophes in the wrong place.
EndIf
;- " "
Case '"'
indentNot = 1
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0 Or *c\c = '"' ; run either to the end of the line (the code is broken in this case), or to the closing quotation mark
AddElement(token())
token()\type = #SYNTAX_String
token()\token = PeekS(*start, (*c - *start) / 2 + 1)
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
;-;
Case ';' ; comment
*start = *c ; memorize the position
; here, instead of a loop, PeekS - PokeS could be used, but in fact they will do the same
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0
AddElement(token())
token()\type = #SYNTAX_Comment
token()\token = PeekS(*start)
Break
; indentNot = 1
;
; here you can make an algorithm for working with comments, for example, to check that there is one space after the semicolon,
; but this can "spoil" commented code
;- ~
Case '~'
indentNot = 1
tilda = 1 ; enable the launch flag/tilde openings
*start = *c ; memorize the position
*c + #Char2
If *c\c <> '"'
AddElement(token())
token()\type = #SYNTAX_Operator
token()\token = "~"
Continue ; if the tilde is used as an inversion of a number, and not the beginning of the escaped string
EndIf
While *c\c
Select *c\c
Case '"'
Select tilda
Case 1, 3
tilda = 2
Case 2
; they came to the closing quotation mark and the flgOpnQt condition below is triggered, since there is no Continue in the text
; tilda = 0
AddElement(token())
token()\type = #SYNTAX_StringTilda
token()\token = PeekS(*start, (*c - *start) / 2 + 1)
Break ; we jump out so as not to make an unnecessary shift, we went through to the closing quotation mark, resetting the tilde is not required
EndSelect
Case '\'
; this mechanism is purely for checking escaped quotation marks after the tilde
; double checking flags changes the behavior when duplicating quotation
Select tilda
Case 2
tilda = 3
Case 3
tilda = 2
EndSelect
EndSelect
*c + #Char2
Wend
;- Space, #TAB
Case ' ', #TAB ; we check the repetition of a space or tab that is not indented and for deletion
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0 Or Not (*c\c = 32 Or *c\c = #TAB) ; we run either to the end of the line (the code in this if it is broken), or to the end of the spaces
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
AddElement(token())
token()\type = #SYNTAX_Space
token()\token = PeekS(*start, (*c - *start) / 2)
Continue
*c - #Char2 ; have you stopped at the non-white? Going back
;- (),
Case '('
AddElement(token())
token()\type = #SYNTAX_Bracket
token()\token = Chr(*c\c)
Case ')', ',', '[', ']'
AddElement(token())
token()\type = #SYNTAX_Separator
token()\token = Chr(*c\c)
;- *
Case '*'
indentNot = 1
*start = *c ; memorize the position
*c + #Char2
If *c\c = 0 ; in fact, the character cannot be at the end of the string
AddElement(token())
token()\type = #SYNTAX_Separator
token()\token = "*"
Break
ElseIf Not ((*c\c >= 'A' And *c\c <= 'Z') Or (*c\c >= 'a' And *c\c <= 'z') Or *c\c = '_') ; if not the beginning of the letters, then the multiplier
AddElement(token())
token()\type = #SYNTAX_Separator
token()\token = "*"
Else ; otherwise, the word that we define as a pointer
While *c\c
Select *c\c
Case 'a' To 'z', 'A' To 'Z', '0' To '9', '_'
*c + #Char2
Default
*c - #Char2 ; backtracking if the character is not one of the above
Break
EndSelect
Wend
AddElement(token())
token()\type = #SYNTAX_Pointer
token()\token = PeekS(*start, (*c - *start) / 2 + 1)
EndIf
;- :
Case ':'
indentNot = 1
*start = *c ; memorize the position
*c + #Char2
If *c\c = ':'
AddElement(token())
token()\type = #SYNTAX_SeparatorModule
token()\token = "::"
Else ; otherwise, the word that we define as a pointer
AddElement(token())
token()\type = #SYNTAX_Separator
token()\token = ":"
*c - #Char2
EndIf
; If *c\c = 0; in fact, the character cannot be at the end of the line ":"
; Break
; EndIf
;- @
Case '@', '?'
*start = *c ; memorize the position
*c + #Char2
While *c\c
Select *c\c
Case 'a' To 'z', 'A' To 'Z', '0' To '9', '_', '$'
*c + #Char2
Default
*c - #Char2 ; backtracking if the character is not one of the above
Break
EndSelect
Wend
AddElement(token())
token()\type = #SYNTAX_Pointer
token()\token = PeekS(*start, (*c - *start) / 2 + 1)
;- #
Case '#'
*start = *c ; memorize the position
*c + #Char2
While *c\c
Select *c\c
Case 'a' To 'z', 'A' To 'Z', '0' To '9', '_' , '$'
*c + #Char2
Default
*c - #Char2 ; backtracking if the character is not one of the above
Break
EndSelect
Wend
AddElement(token())
token()\type = #SYNTAX_Constant
token()\token = PeekS(*start, (*c - *start) / 2 + 1)
;- + / |
Case '+', '/', '|', '&'
AddElement(token())
token()\type = #SYNTAX_Operator
token()\token = Chr(*c\c)
;- = < >
Case '=', '<', '>'
AddElement(token())
token()\type = #SYNTAX_Operator
token()\token = Chr(*c\c)
;- -
Case '-'
AddElement(token())
token()\type = #SYNTAX_Operator
token()\token = Chr(*c\c)
;- .
Case '.'
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0 Or Not ((*c\c >= 'A' And *c\c <= 'Z') Or (*c\c >= 'a' And *c\c <= 'z') Or (*c\c >= '0' And *c\c <= '9') Or *c\c = '_'); we run either to the end of the line (the code in this if it is broken), or to the end of the spaces
AddElement(token())
token()\type = #SYNTAX_Structure
token()\token = PeekS(*start, (*c - *start) / 2)
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
*c - #Char2 ; have you stopped at the non-white? Going back
;- \
Case '\'
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0 Or Not ((*c\c >= 'A' And *c\c <= 'Z') Or (*c\c >= 'a' And *c\c <= 'z') Or (*c\c >= '0' And *c\c <= '9') Or *c\c = '_'); we run either to the end of the line (the code in this if it is broken), or to the end of the spaces
AddElement(token())
token()\type = #SYNTAX_Structure
token()\token = PeekS(*start, (*c - *start) / 2)
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
*c - #Char2 ; have you stopped at the non-white? Going back
;- 0-9
Case '0' To '9'
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0 Or (*c\c < '0' Or *c\c > '9') ; we run either to the end of the line (the code in this if it is broken), or to the end of the spaces
AddElement(token())
token()\type = #SYNTAX_Number
token()\token = PeekS(*start, (*c - *start) / 2)
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
*c - #Char2 ; have you stopped at the non-white? Going back
;- $A-F0-9
Case '$'
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until *c\c = 0 Or Not ((*c\c >= 'A' And *c\c <= 'F') Or (*c\c >= 'a' And *c\c <= 'f') Or (*c\c >= '0' And *c\c <= '9')) ; we run either to the end of the line (the code in this if it is broken), or to the end of the spaces
AddElement(token())
token()\type = #SYNTAX_Number
token()\token = PeekS(*start, (*c - *start) / 2)
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
*c - #Char2 ; have you stopped at the non-white? Going back
;- a-z, A-Z, _
Case 'a' To 'z', 'A' To 'Z', '_'
indentNot = 1
*start = *c ; memorize the position
; Got a quotation mark, run to the closing quotation
Repeat ; scroll to the end of the line
*c + #Char2
Until Not ((*c\c >= 'A' And *c\c <= 'Z') Or (*c\c >= 'a' And *c\c <= 'z') Or (*c\c >= '0' And *c\c <= '9') Or *c\c = '_'); we run either to the end of the line (the code in this if it is broken), or to the end of the spaces
AddElement(token())
If *c\c = '$'
*c + #Char2
token()\type = #SYNTAX_Variable
Else
token()\type = #SYNTAX_Text
*c - #Char2
If *c\c = '_'
token()\type = #SYNTAX_FuncWinAPI
EndIf
*c + #Char2
EndIf
token()\token = PeekS(*start, (*c - *start) / 2)
If *c\c = 0 ; mandatory protection against going beyond the line if the code is invalid
Break
EndIf
Continue
; *c - #Char2 ; have you stopped at the non-white? Going back
; Case 'a' To 'z', 'A' To 'Z', '0' To '9', '_'
; indentNot = 1
;
; *c + #Char2
; While *c\c
; Select *c\c
; Case 'a' To 'z', 'A' To 'Z', '0' To '9', '_'
; *c + #Char2
; Default
; *c - #Char2
; Break
; EndSelect
; Wend
;- Default
; Case '-'
Default
token()\type = #SYNTAX_Unknown
token()\token = Chr(*c\c) ; debase below, but add a character
Debug Str(*c\c) + " = " + Chr(*c\c) ; output a character that does not fit the description
Debug PeekS(*m) ; output a character that does not fit the description
EndSelect
*c + #Char2
Wend
FreeMemory(*m)
; end of line, add hyphen
AddElement(token())
token()\type = #SYNTAX_CRLF
token()\token = #CRLF$
Wend
CloseFile(id_file)
EndIf
;- End CodeParser
; If IsFile(id_file)
; CloseFile(id_file)
; EndIf
; If IsFile(id_file2)
; CloseFile(id_file2)
; EndIf
EndProcedure
;- Global
Global Start, InputFile$, OutputFile$, Rewrite, NotSuccess
Define s1$, s2$, flgCompare = 1, StartTime, result.s
Define NewList token.Token()
Define NewMap KeywordMap.s()
Define NewMap FunctionMap.s()
Define KeywordMap$, FunctionMap$, index, PrevToken
Define WorkingFolder$
WorkingFolder$ = GetPathPart(ProgramFilename())
; Add parameters of the command line to use as a tool
If CountProgramParameters()
InputFile$ = ProgramParameter(0)
If Not (Asc(InputFile$) And FileSize(InputFile$) > 3 And Left(GetExtensionPart(InputFile$), 2) = "pb")
InputFile$ = ""
EndIf
EndIf
InputFile$ = WorkingFolder$ + "test.pb"
; Debug InputFile$
If Not Asc(InputFile$)
InputFile$ = OpenFileRequester("Select PB File", "", "*.pb*|*.pb*|All Files|*.*", 0)
EndIf
KeywordMap$ = ReadFileToVar(WorkingFolder$ + "KeyWordLst.lst")
FunctionMap$ = ReadFileToVar(WorkingFolder$ + "ProcedureLst.lst")
SplitM(KeywordMap$, KeywordMap(), #CRLF$)
SplitM(FunctionMap$, FunctionMap(), #CRLF$)
If Asc(InputFile$)
StartTime = ElapsedMilliseconds()
CodeParser(InputFile$, token())
StartTime = ElapsedMilliseconds() - StartTime
ForEach token()
; If token()\type = #SYNTAX_Text And FindMapElement(KeywordMap(), token()\token)
; token()\type = #SYNTAX_Keyword
; EndIf
If token()\type = #SYNTAX_SeparatorModule
token()\type = #SYNTAX_Separator
PushListPosition(token()) ; remembers
PreviousElement(token()) ; we make the previous
If token()\type = #SYNTAX_Text
token()\type = #SYNTAX_Module
EndIf
PopListPosition(token()) ; we return the current one
EndIf
If token()\type = #SYNTAX_Bracket
PushListPosition(token()) ; remembers
PreviousElement(token()); we make the previous
; index = ListIndex(token())
; Debug index
; SelectElement(token(), index - 1)
If token()\type = #SYNTAX_Space
PreviousElement(token()); we make the previous ещё на один (уже на 2 назад)
; SelectElement(token(), index - 2)
If token()\type = #SYNTAX_Text
token()\type = #SYNTAX_MyFunc
If FindMapElement(KeywordMap(), token()\token)
; Debug "Keyword"
token()\type = #SYNTAX_Keyword
ElseIf FindMapElement(FunctionMap(), token()\token)
; Debug "Function"
token()\type = #SYNTAX_Function
EndIf
EndIf
Else
If token()\type = #SYNTAX_Text
token()\type = #SYNTAX_MyFunc
If FindMapElement(KeywordMap(), token()\token)
; Debug "Keyword"
token()\type = #SYNTAX_Keyword
ElseIf FindMapElement(FunctionMap(), token()\token)
; Debug "Function"
token()\type = #SYNTAX_Function
EndIf
EndIf
EndIf
; SelectElement(token(), index)
PopListPosition(token()) ; we return the current one
EndIf
Next
; ForEach KeywordMap()
; Debug MapKey(KeywordMap())
; If MapKey(KeywordMap()) = "Case"
; Debug 1
; EndIf
; Next
;- Loop
ForEach token()
; Debug "type=" + token()\type
; Debug "|" + token()\token + "|"
Select token()\type
Case #SYNTAX_Text
; If token()\token = "Case"
; Debug "Case"
; EndIf
If FindMapElement(KeywordMap(), token()\token)
; If token()\token = "Case"
; Debug "1"
; EndIf
result + "<font class=kwd>" + token()\token + "</font>"
ElseIf FindMapElement(FunctionMap(), token()\token)
result + "<font class=func>" + token()\token + "</font>"
Else
result + "<font class=txt>" + token()\token + "</font>"
EndIf
Case #SYNTAX_Variable
result + "<font class=var>" + token()\token + "</font>"
Case #SYNTAX_Keyword
result + "<font class=kwd>" + token()\token + "</font>"
Case #SYNTAX_Constant
result + "<font class=const>" + token()\token + "</font>"
Case #SYNTAX_Comment
token()\token = ReplaceString(token()\token, "<", "<")
token()\token = ReplaceString(token()\token, ">", ">")
result + "<font class=cmt>" + token()\token + "</font>"
Case #SYNTAX_String
token()\token = ReplaceString(token()\token, "<", "<")
token()\token = ReplaceString(token()\token, ">", ">")
result + "<font class=str>" + token()\token + "</font>"
Case #SYNTAX_StringTilda
token()\token = ReplaceString(token()\token, "<", "<")
token()\token = ReplaceString(token()\token, ">", ">")
result + "<font class=tilda>" + token()\token + "</font>"
Case #SYNTAX_Function
result + "<font class=func>" + token()\token + "</font>"
Case #SYNTAX_MyFunc
result + "<font class=myfn>" + token()\token + "</font>"
Case #SYNTAX_FuncWinAPI
result + "<font class=fnapi>" + token()\token + "</font>"
Case #SYNTAX_Asm
result + "<font class=Asm>" + token()\token + "</font>"
Case #SYNTAX_Operator
; Debug "|" + token()\token + "|"
; combining operators into a single tag
If PrevToken = #SYNTAX_Operator
result = Left(result, Len(result) - 7) ; cutting off "</font>"
result + token()\token + "</font>"
Else
result + "<font class=oper>" + token()\token + "</font>"
EndIf
Case #SYNTAX_Structure
result + "<font class=struc>" + token()\token + "</font>"
Case #SYNTAX_Number
result + "<font class=num>" + token()\token + "</font>"
Case #SYNTAX_Pointer
result + "<font class=ptr>" + token()\token + "</font>"
Case #SYNTAX_Bracket
result + "<font class=sep>" + token()\token + "</font>"
Case #SYNTAX_Separator
result + "<font class=sep>" + token()\token + "</font>"
Case #SYNTAX_Label
result + "<font class=lbl>" + token()\token + "</font>"
Case #SYNTAX_Module
result + "<font class=mdl>" + token()\token + "</font>"
Case #SYNTAX_Unknown
result + token()\token
Case #SYNTAX_CRLF
result + "<br />" + #CRLF$
Case #SYNTAX_Space
If token()\token <> " "
token()\token = ReplaceString(token()\token, " ", " ")
token()\token = ReplaceString(token()\token, #TAB$, " ")
EndIf
result + token()\token
Case #SYNTAX_Apostrophe
result + "<font class=apostr>" + token()\token + "</font>"
EndSelect
PrevToken = token()\type
Next
EndIf
Define id_file2
id_file2 = CreateFile(#PB_Any, WorkingFolder$ + "test.html")
If id_file2
WriteString(id_file2, "<html><head><title>Example</title><META http-equiv='Content-Type' content='text/html; charset=utf-8'></META><link href='style.css' rel='stylesheet' type='text/css'></head><body><p class='codebox1'>" + #CRLF$ + #CRLF$)
WriteString(id_file2, result + #CRLF$ + #CRLF$)
WriteString(id_file2, "</p></body></html>")
CloseFile(id_file2)
EndIf