Compiler/Verifying syntax: Difference between revisions

m
m (→‎{{header|Raku}}: Revert attempt to placate syntax highlighter. Interferes with parse)
m (→‎{{header|Wren}}: Minor tidy)
 
(10 intermediate revisions by 5 users not shown)
Line 47:
=={{header|ALGOL W}}==
Includes the test cases from the Go sample. Note, strings are limited to 256 characters in Algol W.
<langsyntaxhighlight lang="algolw">begin
% verify expressions match expected syntax %
procedure stmt ( string(256) value text ) ; begin
Line 224:
stmt( "j & k" );
stmt( "l or _m" )
end.</langsyntaxhighlight>
{{out}}
<pre>
Line 263:
 
=={{header|C}}==
<langsyntaxhighlight Clang="c">// cverifyingsyntaxrosetta.c
// http://www.rosettacode.org/wiki/Compiler/_Verifying_Syntax
 
Line 367:
{
for( int i = 0; i < sizeof(tests)/sizeof(*tests); i++ ) parse(tests[i]);
}</langsyntaxhighlight>
{{out}}
<pre>
Line 418:
 
In particular, after substitutions, "= not", "+ not" etc. would be allowed by the Go parser so we need to exclude them. Curiously, the Go parser allows something like "2 < 3 < 4" even though it doesn't compile. We need therefore to exclude that also (see Talk page).
<langsyntaxhighlight lang="go">package main
 
import (
Line 519:
fmt.Println()
}
}</langsyntaxhighlight>
 
{{out}}
Line 622:
"false" -> identifier cannot begin with an underscore
</pre>
 
=={{header|jq}}==
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
 
This entry uses the PEG (Parsing Expression Grammar) formalism
to transform the given grammar to a jq verification program
by a simple process that amounts to transcription.
 
For example, in the rule for `primary`, the alternation
 
Identifier | Integer
 
becomes the jq expression:
 
Identifer // Integer
 
The transcription process is not completely trivial as
jq requires definitions be ordered and perhaps nested
to satisfy a "define-before-use" rule. In the present case,
since `primary` and `expr` are defined circularly,
we define `primary` as an inner function of `expr`.
 
This PEG-to-jq transcription process is
described in detail at
[https://github.com/stedolan/jq/wiki/Parsing-Expression-Grammars].
 
The following presentation uses jq's support for regular expressions
for the sake of simplicity, brevity and efficiency.
For example, the grammar rule:
 
Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
 
becomes the jq program:
 
def Digit: parse("[0-9]");
 
where `parse` is a utility function defined in the library
of PEG-oriented functions in the first subsection below.
 
The jq program presented here works on character strings and textual files, and hence
the use of `ws` (for whitespace) in the program. Since `ws` is defined here
to make whitespace optional, it might be desirable to modify the program
to require whitespace (e.g. using the utility function `_`) in certain places instead.
</syntaxhighlight>
====Generic PEG Library====
The jq module at [[:Category:Jq/peg.jq]] can be included by copying it to a file,
and adding an `include` statement to top of the main program, e.g. as follows:
<syntaxhighlight lang=jq>
include "peg" {search: "."};
</syntaxhighlight>
 
====The Grammar====
<syntaxhighlight lang=jq>
def expr:
def Digit : parse("[0-9]");
def Letter : parse("[a-zA-Z]");
def Identifier : Letter | star(Letter // Digit // literal("_"));
def Integer : plus(Digit);
def primary : ws
| (Identifier
// Integer
// (literal("(") | expr | literal(")"))
// literal("true")
// literal("false"))
| ws;
def expr_level_6 : primary | star((literal("*") // literal("/")) | primary) ;
def expr_level_5 : expr_level_6 | star((literal("+") // literal("-")) | expr_level_6) ;
def expr_level_4 : ws | optional(literal("not")) | expr_level_5 | optional(parse("[=<]") | expr_level_5) ;
def expr_level_3 : expr_level_4 | star(literal("and") | expr_level_4) ;
def expr_level_2 : expr_level_3 | star(literal("or") | expr_level_3) ;
 
ws | expr_level_2 | ws;
 
def stmt:
{remainder: .} | expr | eos;
</syntaxhighlight>
====The Go examples====
<syntaxhighlight lang=jq>
def go: [
"$",
"one",
"either or both",
"a + 1",
"a + b < c",
"a = b",
"a or b = c",
"3 + not 5",
"3 + (not 5)",
"(42 + 3",
"(42 + 3)",
" not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true",
" and 3 < 2",
"not 7 < 2",
"2 < 3 < 4",
"2 < (3 < 4)",
"2 < foobar - 3 < 4",
"2 < foobar and 3 < 4",
"4 * (32 - 16) + 9 = 73",
"235 76 + 1",
"true or false = not true",
"true or false = (not true)",
"not true or false = false",
"not true = false",
"a + b = not c and false",
"a + b = (not c) and false",
"a + b = (not c and false)",
"ab_c / bd2 or < e_f7",
"g not = h",
"été = false",
"i++",
"j & k",
"l or _m"
];
 
# For ease of comparison with the Go output, simply emit `true` or `false`
go[]
| (stmt | true) // false
</syntaxhighlight>
 
'''Invocation''': jq -nr -f compiler-verifying-syntax.jq
{{output}}
The same sequence of `true` and `false` values as at [[#Go|Go]].
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">function substituteinnerparentheses(s, subs)
((i = findlast('(', s)) == nothing) && return (s, false)
((j = findfirst(')', s[i:end])) == nothing) && return (s, false)
Line 676 ⟶ 804:
println("The compiler parses the statement { $s } and outputs: ", okparse(s))
end
</langsyntaxhighlight>{{out}}
<pre>
The compiler parses the statement { not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true } and outputs: true
Line 687 ⟶ 815:
The compiler parses the statement { 2 < 5 < 9 } and outputs: false
</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import strutils, tables
 
type
 
# List of tokens with their textual representation.
Token = enum tkError = "invalid token", tkIdent = "identifier", tkInt = "integer",
tkLPar = "'('", tkRPar = "')'", tkFalse = "'false'", tkTrue = "'true'",
tkLt = "'<'", tkEq = "'='", tkAdd = "'+'", tkSub = "'-'", tkMul = "'*'",
tkDiv = "'/'", tkOr = "'or'", tkAnd = "'and'", tkNot = "'not'", tkEOF = "EOF"
 
Lexer = object
str: string # String to parse.
len: Natural # String length.
pos: int # Current lexer position.
token: Token # Current token.
error: string # Error message.
 
const
# Mapping of reserved identifiers to tokens.
IdentTokens = {"false": tkFalse, "true": tkTrue, "or": tkOr, "and": tkAnd, "not": tkNot}.toTable
# Mapping of characters to tokens.
CharTokens = {'(': tkLPar, ')': tkRPar, '<': tkLt, '=': tkEq,
'+': tkAdd, '-': tkSub, '*': tkMul, '/': tkDiv}.toTable
 
 
####################################################################################################
# Lexer.
 
# Forward reference.
func nextToken(lex: var Lexer)
 
 
func initLexer(str: string): Lexer =
## Initialize a lexer.
result = Lexer(str: str, len: str.len, pos: 0)
result.nextToken() # Always a token ahead.
 
 
func getIdToken(lex: var Lexer) =
## Get the token for an identifier.
var str: string
while lex.pos < lex.len and lex.str[lex.pos] in IdentChars:
str.add lex.str[lex.pos]
inc lex.pos
lex.token = IdentTokens.getOrDefault(str, tkIdent)
 
 
func getInt(lex: var Lexer) =
## Get an integer token.
while lex.pos < lex.len and lex.str[lex.pos] in Digits:
inc lex.pos
lex.token = tkInt
 
 
func nextToken(lex: var Lexer) =
## Find the next token.
 
# Skip spaces.
while lex.pos < lex.str.len and lex.str[lex.pos] == ' ':
inc lex.pos
 
if lex.pos == lex.str.len:
lex.token = tkEOF
 
else:
let ch = lex.str[lex.pos]
case ch
of 'a'..'z':
lex.getIdToken()
of '0'..'9':
lex.getint()
else:
inc lex.pos
lex.token = CharTokens.getOrDefault(ch, tkError)
 
 
####################################################################################################
# Parser.
 
# Forward reference.
proc checkExpr(lex: var Lexer): bool
 
 
proc checkPrimary(lex: var Lexer): bool =
## Check validity of a primary.
 
if lex.token in {tkIdent, tkInt, tkFalse, tkTrue}:
lex.nextToken()
return true
 
elif lex.token == tkLPar:
lex.nextToken()
if not lex.checkExpr():
return false
if lex.token != tkRPar:
lex.error = "Encountered $#; expected ')'.".format(lex.token)
return false
else:
lex.nextToken()
return true
 
else:
lex.error = "Encountered $#; expected identifier, litteral or '('.".format(lex.token)
return false
 
 
proc checkExpr6(lex: var Lexer): bool =
## Check validity of an expr6.
 
if not lex.checkPrimary(): return false
while lex.token in [tkMul, tkDiv]:
lex.nextToken()
if not lex.checkPrimary(): return false
result = true
 
 
proc checkExpr5(lex: var Lexer): bool =
## Check validity of an expr5.
 
if not lex.checkExpr6(): return false
while lex.token in [tkAdd, tkSub]:
lex.nextToken()
if not lex.checkExpr6(): return false
result = true
 
 
proc checkExpr4(lex: var Lexer): bool =
## Check validity of an expr4.
 
if lex.token == tkNot: lex.nextToken()
if not lex.checkExpr5(): return false
if lex.token in [tkLt, tkEq]:
lex.nextToken()
if not lex.checkExpr5(): return false
result = true
 
 
proc checkExpr3(lex: var Lexer): bool =
## Check validity of an expr3.
 
if not lex.checkExpr4(): return false
while lex.token == tkAnd:
lex.nextToken()
if not lex.checkExpr4(): return false
result = true
 
 
proc checkExpr2(lex: var Lexer): bool =
## Check validity of an expr2.
 
if not lex.checkExpr3(): return false
while lex.token == tkOr:
lex.nextToken()
if not lex.checkExpr3(): return false
result = true
 
 
proc checkExpr(lex: var Lexer): bool =
## Check validity of an expr.
lex.checkExpr2()
 
 
proc checkStmt(lex: var Lexer): bool =
## Check validity of a statement.
 
result = lex.checkExpr()
if result and lex.pos < lex.len:
lex.error = "Extra characters at end of statement."
result = false
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
# Using test set from Algol68 version.
 
const Tests = ["wombat",
"wombat or monotreme",
"( wombat and not )",
"wombat or not",
"a + 1",
"a + b < c",
"a + b - c * d / e < f and not ( g = h )",
"a + b - c * d / e < f and not ( g = h",
"a = b",
"a or b = c",
"$",
"true or false = not true",
"not true = false",
"3 + not 5",
"3 + (not 5)",
"(42 + 3",
" not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true",
" and 3 < 2",
"not 7 < 2",
"2 < 3 < 4",
"2 < foobar - 3 < 4",
"2 < foobar and 3 < 4",
"4 * (32 - 16) + 9 = 73",
"235 76 + 1",
"a + b = not c and false",
"a + b = (not c) and false",
"a + b = (not c and false)",
"ab_c / bd2 or < e_f7",
"g not = h",
"été = false",
"i++",
"j & k",
"l or _m"]
 
for test in Tests:
var lex = initLexer(test)
let ok = checkStmt(lex)
echo test, " → ", ok
if not ok: echo "*** Error at position $1. $2 ".format(lex.pos, lex.error)</syntaxhighlight>
 
{{out}}
<pre>wombat → true
wombat or monotreme → true
( wombat and not ) → false
*** Error at position 18. Encountered ')'; expected identifier, litteral or '('.
wombat or not → false
*** Error at position 13. Encountered EOF; expected identifier, litteral or '('.
a + 1 → true
a + b < c → true
a + b - c * d / e < f and not ( g = h ) → true
a + b - c * d / e < f and not ( g = h → false
*** Error at position 37. Encountered EOF; expected ')'.
a = b → true
a or b = c → true
$ → false
*** Error at position 1. Encountered invalid token; expected identifier, litteral or '('.
true or false = not true → false
*** Error at position 19. Encountered 'not'; expected identifier, litteral or '('.
not true = false → true
3 + not 5 → false
*** Error at position 7. Encountered 'not'; expected identifier, litteral or '('.
3 + (not 5) → true
(42 + 3 → false
*** Error at position 7. Encountered EOF; expected ')'.
not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true → true
and 3 < 2 → false
*** Error at position 4. Encountered 'and'; expected identifier, litteral or '('.
not 7 < 2 → true
2 < 3 < 4 → false
*** Error at position 7. Extra characters at end of statement.
2 < foobar - 3 < 4 → false
*** Error at position 16. Extra characters at end of statement.
2 < foobar and 3 < 4 → true
4 * (32 - 16) + 9 = 73 → true
235 76 + 1 → false
*** Error at position 6. Extra characters at end of statement.
a + b = not c and false → false
*** Error at position 11. Encountered 'not'; expected identifier, litteral or '('.
a + b = (not c) and false → true
a + b = (not c and false) → true
ab_c / bd2 or < e_f7 → false
*** Error at position 15. Encountered '<'; expected identifier, litteral or '('.
g not = h → false
*** Error at position 5. Extra characters at end of statement.
été = false → false
*** Error at position 1. Encountered invalid token; expected identifier, litteral or '('.
i++ → false
*** Error at position 3. Encountered '+'; expected identifier, litteral or '('.
j & k → false
*** Error at position 3. Extra characters at end of statement.
l or _m → false
*** Error at position 6. Encountered invalid token; expected identifier, litteral or '('.</pre>
 
=={{header|Perl}}==
Line 692 ⟶ 1,090:
Added 'not' and non-assoc fixes.
Cooler output.
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # http://www.rosettacode.org/wiki/Compiler/_Verifying_Syntax
Line 749 ⟶ 1,147:
j & k
l or _m
UPPER_cAsE_aNd_letter_and_12345_test</langsyntaxhighlight>
{{out}}
<pre>
Line 789 ⟶ 1,187:
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>-- demo\rosetta\Compiler\Verify_Syntax.exw
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Compiler\Verify_Syntax.exw</span>
string src
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
integer ch, sdx
<span style="color: #004080;">string</span> <span style="color: #000000;">src</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">sdx</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">skip_spaces</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">sdx</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">src</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">src</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\t'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\r'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">INTEGER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">IDENT</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ERROR</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">EOF</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">toktypes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"SYMBOL"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"INTEGER"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"IDENT"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ERROR"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"EOF"</span><span style="color: #0000FF;">}</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tok</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">sprintok</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span><span style="color: #0000FF;">)</span>
procedure skip_spaces()
<span style="color: #000000;">tok</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">toktypes</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]]</span>
while 1 do
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">})</span>
if sdx>length(src) then exit end if
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
ch = src[sdx]
if not find(ch," \t\r\n") then exit end if
sdx += 1
end while
end procedure
<span style="color: #008080;">procedure</span> <span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
enum SYMBOL, INTEGER, IDENT, ERROR, EOF
<span style="color: #000080;font-style:italic;">-- yeilds one of:
constant toktypes = {"SYMBOL","INTEGER","IDENT","ERROR","EOF"}
-- {SYMBOL,ch} where ch is one of "()+-/*=&&lt;", or
sequence tok
-- {INTEGER,n}, or
 
function -- sprintok( {IDENT,string}, fmt)or
-- {ERROR,msg}, or
tok[1] = toktypes[tok[1]]
-- {EOF}</span>
return sprintf(fmt,{tok})
<span style="color: #000000;">skip_spaces</span><span style="color: #0000FF;">()</span>
end function
<span style="color: #004080;">integer</span> <span style="color: #000000;">tokstart</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sdx</span>
 
<span style="color: #008080;">if</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">ERROR</span> <span style="color: #008080;">then</span>
procedure next_token()
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"erm, tok is"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- looping??</span>
-- yeilds one of:
<span style="color: #008080;">elsif</span> <span style="color: #000000;">sdx</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">src</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
-- {SYMBOL,ch} where ch is one of "()+-/*=&<", or
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">EOF</span><span style="color: #0000FF;">}</span>
-- {INTEGER,n}, or
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"()+-/*=&&lt;"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
-- {IDENT,string}, or
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
-- {ERROR,msg}, or
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">&</span><span style="color: #008000;">""</span><span style="color: #0000FF;">}</span>
-- {EOF}
<span style="color: #008080;">elsif</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'9'</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
skip_spaces()
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
integer tokstart = sdx
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
if tok[1]=ERROR then
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
?{"erm, tok is",tok} -- looping??
<span style="color: #008080;">if</span> <span style="color: #000000;">sdx</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">src</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
elsif sdx>length(src) then
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">src</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span>
tok = {EOF}
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
elsif find(ch,"()+-/*=&<") then
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">*</span><span style="color: #000000;">10</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
sdx += 1
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
tok = {SYMBOL,ch&""}
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">INTEGER</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">}</span>
elsif (ch>='0' and ch<='9') then
<span style="color: #008080;">elsif</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'a'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'z'</span><span style="color: #0000FF;">)</span>
integer n = ch-'0'
<span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'Z'</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
while true do
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
sdx += 1
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
if sdx>length(src) then exit end if
<span style="color: #008080;">if</span> <span style="color: #000000;">sdx</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">src</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
ch = src[sdx]
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">src</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span>
if ch<'0' or ch>'9' then exit end if
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">'_'</span>
n = n*10 + ch-'0'
<span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'a'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'z'</span><span style="color: #0000FF;">)</span>
end while
<span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'Z'</span><span style="color: #0000FF;">)</span>
tok = {INTEGER,n}
<span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'9'</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
elsif (ch>='a' and ch<='z')
<span style="color: #008080;">exit</span>
or (ch>='A' and ch<='Z') then
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
while true do
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
sdx += 1
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">IDENT</span><span style="color: #0000FF;">,</span><span style="color: #000000;">src</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tokstart</span><span style="color: #0000FF;">..</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]}</span>
if sdx>length(src) then exit end if
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'_'</span> <span style="color: #008080;">then</span>
ch = src[sdx]
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ERROR</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"identifiers may not start with _"</span><span style="color: #0000FF;">}</span>
if ch!='_'
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
and (ch<'a' or ch>'z')
<span style="color: #008080;">else</span>
and (ch<'A' or ch>'Z')
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ERROR</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"illegal char (%c/%d)"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)}</span>
and (ch<'0' or ch>'9') then
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
exit
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end while
tok = {IDENT,src[tokstart..sdx-1]}
elsif ch='_' then
tok = {ERROR,"identifiers may not start with _"}
sdx += 1
else
tok = {ERROR,sprintf("illegal char (%c/%d)",ch)}
sdx += 1
end if
end procedure
 
forward procedure or_expr()
 
procedure primary()
integer tt = tok[1]
if tt=IDENT
or tt=INTEGER then
next_token()
elsif tok={SYMBOL,"("} then
next_token()
or_expr()
if tok!={SYMBOL,")"} then
tok = {ERROR,") expected"}
else
next_token()
end if
else
tok = {ERROR,sprintok("invalid [%v]")}
end if
end procedure
 
procedure mul_expr()
while true do
primary()
if not find(tok,{{SYMBOL,"*"},{SYMBOL,"/"}}) then exit end if
next_token()
end while
end procedure
 
procedure sum_expr()
while true do
mul_expr()
if not find(tok,{{SYMBOL,"+"},{SYMBOL,"-"}}) then exit end if
next_token()
end while
end procedure
 
procedure cmp_expr()
if tok=={IDENT,"not"} then next_token() end if
sum_expr()
if find(tok,{{SYMBOL,"="},{SYMBOL,"<"}}) then
next_token()
sum_expr()
end if
end procedure
 
procedure and_expr()
while true do
cmp_expr()
if tok!={IDENT,"and"} then exit end if
next_token()
end while
end procedure
 
procedure or_expr()
while true do
and_expr()
if tok!={IDENT,"or"} then exit end if
next_token()
end while
end procedure
 
procedure statement()
or_expr()
end procedure
<span style="color: #008080;">forward</span> <span style="color: #008080;">procedure</span> <span style="color: #000000;">or_expr</span><span style="color: #0000FF;">()</span>
procedure verify_syntax(string source)
src = source
<span style="color: #008080;">procedure</span> <span style="color: #000000;">primary</span><span style="color: #0000FF;">()</span>
sdx = 1
<span style="color: #004080;">integer</span> <span style="color: #000000;">tt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
tok = {0} -- ("not error"/invalid-ish)
<span style="color: #008080;">if</span> <span style="color: #000000;">tt</span><span style="color: #0000FF;">=</span><span style="color: #000000;">IDENT</span>
next_token()
<span style="color: #008080;">or</span> <span style="color: #000000;">tt</span><span style="color: #0000FF;">=</span><span style="color: #000000;">INTEGER</span> <span style="color: #008080;">then</span>
statement()
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
printf(1,"%30s ==> %s\n",{source,iff(tok[1]=EOF?"true":sprintok("false [tok=%v]"))})
<span style="color: #008080;">elsif</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">={</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"("</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">then</span>
end procedure
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
 
<span style="color: #000000;">or_expr</span><span style="color: #0000FF;">()</span>
constant tests = {
<span style="color: #008080;">if</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">!={</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">")"</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">then</span>
"$",
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ERROR</span><span style="color: #0000FF;">,</span><span style="color: #008000;">") expected"</span><span style="color: #0000FF;">}</span>
"one",
<span style="color: #008080;">else</span>
"either or both",
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
"a + 1",
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
"a + b < c",
<span style="color: #008080;">else</span>
"a = b",
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ERROR</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sprintok</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"invalid [%v]"</span><span style="color: #0000FF;">)}</span>
"a or b = c",
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
"3 + not 5",
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
"3 + (not 5)",
"(42 + 3",
<span style="color: #008080;">procedure</span> <span style="color: #000000;">mul_expr</span><span style="color: #0000FF;">()</span>
"(42 + 3)",
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
" not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true",
<span style="color: #000000;">primary</span><span style="color: #0000FF;">()</span>
" and 3 < 2",
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"*"</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"/"</span><span style="color: #0000FF;">}})</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
"not 7 < 2",
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
"2 < 3 < 4",
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
"2 < (3 < 4)",
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
"2 < foobar - 3 < 4",
"2 < foobar and 3 < 4",
<span style="color: #008080;">procedure</span> <span style="color: #000000;">sum_expr</span><span style="color: #0000FF;">()</span>
"4 * (32 - 16) + 9 = 73",
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
"235 76 + 1",
<span style="color: #000000;">mul_expr</span><span style="color: #0000FF;">()</span>
"true or false = not true",
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+"</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"-"</span><span style="color: #0000FF;">}})</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
"true or false = (not true)",
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
"not true or false = false",
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
"not true = false",
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
"a + b = not c and false",
"a + b = (not c) and false",
<span style="color: #008080;">procedure</span> <span style="color: #000000;">cmp_expr</span><span style="color: #0000FF;">()</span>
"a + b = (not c and false)",
<span style="color: #008080;">if</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">=={</span><span style="color: #000000;">IDENT</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"not"</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">then</span> <span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
"ab_c / bd2 or < e_f7",
<span style="color: #000080;font-style:italic;">-- while true do
"g not = h",
-- "i++",sum_expr()
-- if not find(tok,{{SYMBOL,"="},{SYMBOL,"&lt;"}}) then exit end if
"j & k",
-- "l or _m"}next_token()
-- end while</span>
 
<span style="color: #000000;">sum_expr</span><span style="color: #0000FF;">()</span>
printf(1,"Verify Syntax:\n")
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"="</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">SYMBOL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"&lt;"</span><span style="color: #0000FF;">}})</span> <span style="color: #008080;">then</span>
for i=1 to length(tests) do
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
verify_syntax(tests[i])
<span style="color: #000000;">sum_expr</span><span style="color: #0000FF;">()</span>
end for</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">and_expr</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">cmp_expr</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">!={</span><span style="color: #000000;">IDENT</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"and"</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">or_expr</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">and_expr</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">tok</span><span style="color: #0000FF;">!={</span><span style="color: #000000;">IDENT</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"or"</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">statement</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">or_expr</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">verify_syntax</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">source</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">src</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">source</span>
<span style="color: #000000;">sdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">tok</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- ("not error"/invalid-ish)</span>
<span style="color: #000000;">next_token</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">statement</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%30s ==&gt; %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">source</span><span style="color: #0000FF;">,</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tok</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">EOF</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"true"</span><span style="color: #0000FF;">:</span><span style="color: #000000;">sprintok</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"false [tok=%v]"</span><span style="color: #0000FF;">))})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span>
<span style="color: #008000;">"$"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"one"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"either or both"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a + 1"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a + b &lt; c"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a = b"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a or b = c"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"3 + not 5"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"3 + (not 5)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"(42 + 3"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"(42 + 3)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">" not 3 &lt; 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 &lt; 56) and 4 * 3 &lt; 12 or not true"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">" and 3 &lt; 2"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"not 7 &lt; 2"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"2 &lt; 3 &lt; 4"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"2 &lt; (3 &lt; 4)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"2 &lt; foobar - 3 &lt; 4"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"2 &lt; foobar and 3 &lt; 4"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"4 * (32 - 16) + 9 = 73"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"235 76 + 1"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"true or false = not true"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"true or false = (not true)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"not true or false = false"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"not true = false"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a + b = not c and false"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a + b = (not c) and false"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"a + b = (not c and false)"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"ab_c / bd2 or &lt; e_f7"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"g not = h"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"i++"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"j & k"</span><span style="color: #0000FF;">,</span>
<span style="color: #008000;">"l or _m"</span><span style="color: #0000FF;">}</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Verify Syntax:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">verify_syntax</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
Note that "= not c" fails, whereas "= (not c)" passes, see talk page. (Arguably the task definition should be fixed.)
Line 1,012 ⟶ 1,421:
=={{header|Raku}}==
Format of task grammar is changed from EBNF to ABNF to cater for the Grammar::ABNF module and testing data is taken from the Perl entry.
<syntaxhighlight lang="raku" perl6line># 20200511 Raku programming solution
 
use Grammar::ABNF;
Line 1,063 ⟶ 1,472:
DATA
 
say $g.parse($_).Bool, "\t", $_ for DATA.lines</langsyntaxhighlight>
{{out}}
<pre>False 3 + not 5
Line 1,086 ⟶ 1,495:
False l or _m
True UPPER_cAsE_aNd_letter_and_12345_test
</pre>
 
=={{header|Wren}}==
{{trans|Nim}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-str}}
<syntaxhighlight lang="wren">import "./dynamic" for Enum
import "./str" for Char
 
var Token = Enum.create(
"Token", ["error", "ident", "int", "lpar", "rpar", "False", "True",
"lt", "eq", "add", "sub", "mul", "div", "or", "and", "not", "eof"]
)
 
var Token2Text = {
Token.error: "invalid token", Token.ident: "identifier", Token.int: "integer",
Token.lpar: "'('", Token.rpar: "')'", Token.False: "'false'", Token.True: "'true'",
Token.lt: "'<'", Token.eq: "'='", Token.add: "'+'", Token.sub: "'-'",
Token.mul: "'*'", Token.div: "'/'", Token.or: "'or'", Token.and: "'and'",
Token.not: "'not'", Token.eof: "EOF"
}
 
var IdentTokens = {
"false": Token.False, "true": Token.True, "or": Token.or,
"and": Token.and, "not": Token.not
}
 
var CharTokens = {
"(": Token.lpar, ")": Token.rpar, "<": Token.lt, "=": Token.eq,
"+": Token.add, "-": Token.sub, "*": Token.mul, "/": Token.div
}
 
var IsIdentChar = Fn.new { |c| Char.isAsciiAlphaNum(c) || c == "_" }
 
class Lexer {
static init(s) {
var lex = Lexer.new(s, s.count, 0, "", "")
lex.nextToken
return lex
}
 
construct new(str, len, pos, token, error) {
_str = str // string to parse
_len = len // string length
_pos = pos // current lexer position
_token = token // current token
_error = error // error message
}
 
// property getters required
pos { _pos }
error { _error }
 
// get the token for an identifier
getIdToken {
var s = ""
while (_pos < _len && IsIdentChar.call(_str[_pos])) {
s = s + _str[_pos]
_pos = _pos + 1
}
_token = IdentTokens.containsKey(s) ? IdentTokens[s] : Token.ident
}
 
// get an integer token
getInt {
while (_pos < _len && Char.isDigit(_str[_pos])) _pos = _pos + 1
_token = Token.int
}
 
// find the next token
nextToken {
// skip spaces
while (_pos < _len && _str[_pos] == " ") _pos = _pos + 1
if (_pos == _len) {
_token = Token.eof
} else {
var ch = _str[_pos]
if (Char.isAsciiLower(ch)) {
getIdToken
} else if (Char.isDigit(ch)) {
getInt
} else {
_pos = _pos + 1
_token = CharTokens.containsKey(ch) ? CharTokens[ch] : Token.error
}
}
}
 
// check validity of a primary
checkPrimary {
if ([Token.ident, Token.int, Token.False, Token.True].contains(_token)) {
nextToken
return true
} else if (_token == Token.lpar) {
nextToken
if (!checkExpr) return false
if (_token != Token.rpar) {
_error = "Encountered %(Token2Text[_token]); expected ')'"
return false
} else {
nextToken
return true
}
} else {
_error = "Encountered %(Token2Text[_token]); expected identifier, literal or '('"
return false
}
}
 
// check validity of an expr6
checkExpr6 {
if (!checkPrimary) return false
while ([Token.mul, Token.div].contains(_token)) {
nextToken
if (!checkPrimary) return false
}
return true
}
 
// check validity of an expr5
checkExpr5 {
if (!checkExpr6) return false
while ([Token.add, Token.sub].contains(_token)) {
nextToken
if (!checkExpr6) return false
}
return true
}
 
// check validity of an expr4
checkExpr4 {
if (_token == Token.not) nextToken
if (!checkExpr5) return false
if ([Token.lt, Token.eq].contains(_token)) {
nextToken
if (!checkExpr5) return false
}
return true
}
 
// check validity of an expr3
checkExpr3 {
if (!checkExpr4) return false
while (_token == Token.and) {
nextToken
if (!checkExpr4) return false
}
return true
}
 
// check validity of an expr2
checkExpr2 {
if (!checkExpr3) return false
while (_token == Token.or) {
nextToken
if (!checkExpr3) return false
}
return true
}
 
// check validity of an expr
checkExpr { checkExpr2 }
 
// check validity of a statement
checkStmt {
var result = checkExpr
if (result && _pos < _len) {
_error = "Extra characters at end of statement."
result = false
}
return result
}
}
 
// using test set from Algol68 version
 
var tests = [
"wombat",
"wombat or monotreme",
"( wombat and not )",
"wombat or not",
"a + 1",
"a + b < c",
"a + b - c * d / e < f and not ( g = h )",
"a + b - c * d / e < f and not ( g = h",
"a = b",
"a or b = c",
"$",
"true or false = not true",
"not true = false",
"3 + not 5",
"3 + (not 5)",
"(42 + 3",
" not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true",
" and 3 < 2",
"not 7 < 2",
"2 < 3 < 4",
"2 < foobar - 3 < 4",
"2 < foobar and 3 < 4",
"4 * (32 - 16) + 9 = 73",
"235 76 + 1",
"a + b = not c and false",
"a + b = (not c) and false",
"a + b = (not c and false)",
"ab_c / bd2 or < e_f7",
"g not = h",
"été = false",
"i++",
"j & k",
"l or _m"
]
 
for (test in tests) {
var lex = Lexer.init(test)
var ok = lex.checkStmt
System.print("%(test) -> %(ok)")
if (!ok) {
System.print("*** Error at position %(lex.pos). %(lex.error)\n")
}
}</syntaxhighlight>
 
{{out}}
<pre>
wombat -> true
wombat or monotreme -> true
( wombat and not ) -> false
*** Error at position 18. Encountered ')'; expected identifier, literal or '('
 
wombat or not -> false
*** Error at position 13. Encountered EOF; expected identifier, literal or '('
 
a + 1 -> true
a + b < c -> true
a + b - c * d / e < f and not ( g = h ) -> true
a + b - c * d / e < f and not ( g = h -> false
*** Error at position 37. Encountered EOF; expected ')'
 
a = b -> true
a or b = c -> true
$ -> false
*** Error at position 1. Encountered invalid token; expected identifier, literal or '('
 
true or false = not true -> false
*** Error at position 19. Encountered 'not'; expected identifier, literal or '('
 
not true = false -> true
3 + not 5 -> false
*** Error at position 7. Encountered 'not'; expected identifier, literal or '('
 
3 + (not 5) -> true
(42 + 3 -> false
*** Error at position 7. Encountered EOF; expected ')'
 
not 3 < 4 or (true or 3 / 4 + 8 * 5 - 5 * 2 < 56) and 4 * 3 < 12 or not true -> true
and 3 < 2 -> false
*** Error at position 4. Encountered 'and'; expected identifier, literal or '('
 
not 7 < 2 -> true
2 < 3 < 4 -> false
*** Error at position 7. Extra characters at end of statement.
 
2 < foobar - 3 < 4 -> false
*** Error at position 16. Extra characters at end of statement.
 
2 < foobar and 3 < 4 -> true
4 * (32 - 16) + 9 = 73 -> true
235 76 + 1 -> false
*** Error at position 6. Extra characters at end of statement.
 
a + b = not c and false -> false
*** Error at position 11. Encountered 'not'; expected identifier, literal or '('
 
a + b = (not c) and false -> true
a + b = (not c and false) -> true
ab_c / bd2 or < e_f7 -> false
*** Error at position 15. Encountered '<'; expected identifier, literal or '('
 
g not = h -> false
*** Error at position 5. Extra characters at end of statement.
 
été = false -> false
*** Error at position 1. Encountered invalid token; expected identifier, literal or '('
 
i++ -> false
*** Error at position 3. Encountered '+'; expected identifier, literal or '('
 
j & k -> false
*** Error at position 3. Extra characters at end of statement.
 
l or _m -> false
*** Error at position 6. Encountered invalid token; expected identifier, literal or '('
</pre>
9,482

edits