182 lines
4.6 KiB
Text
182 lines
4.6 KiB
Text
-- demo\\rosetta\\Compiler\\lex.e
|
|
-- The reusable part of lex.exw
|
|
-- This is only kept separate from core.e for consistency with later modules.
|
|
with javascript_semantics
|
|
include core.e
|
|
|
|
integer ch = ' ',
|
|
line = 0,
|
|
col = 0
|
|
|
|
procedure eof(string s)
|
|
error("%s in %s literal",{iff(ch=EOF?"EOF":"EOL"),s})
|
|
end procedure
|
|
|
|
function next_ch()
|
|
while 1 do
|
|
col += 1
|
|
if oneline=EOF then
|
|
ch = EOF
|
|
exit
|
|
elsif col>length(oneline) then
|
|
line += 1
|
|
col = 0
|
|
oneline = iff(platform()=JS?js_gets(input_file)
|
|
:gets(input_file))
|
|
else
|
|
ch = oneline[col]
|
|
exit
|
|
end if
|
|
end while
|
|
return ch
|
|
end function
|
|
|
|
-- for pwa/p2js (JavaScript *really* dislikes tabs in strings):
|
|
--constant whitespace = " \t\r\n\x0B\xA0"
|
|
constant whitespace = {' ','\t','\r','\n',#0B,#A0}
|
|
-- (0x0B is Vertical Tab, 0xA0 is Non-breaking space)
|
|
|
|
procedure skipspacesandcomments()
|
|
while 1 do
|
|
if not find(ch,whitespace) then
|
|
if ch='/' and col<length(oneline) and oneline[col+1]='*' then
|
|
tok_line = line -- (in case of EOF error)
|
|
tok_col = col
|
|
ch = next_ch() -- (can be EOF)
|
|
ch = next_ch() -- ( "" )
|
|
while 1 do
|
|
if ch='*' then
|
|
ch = next_ch()
|
|
if ch='/' then exit end if
|
|
elsif ch=EOF then
|
|
error("EOF in comment")
|
|
else
|
|
ch = next_ch()
|
|
end if
|
|
end while
|
|
else
|
|
exit
|
|
end if
|
|
end if
|
|
ch = next_ch()
|
|
end while
|
|
end procedure
|
|
|
|
function escape_char(string s)
|
|
ch = next_ch() -- (discard the '\\')
|
|
if ch='n' then
|
|
ch = '\n'
|
|
elsif ch='\\' then
|
|
ch = '\\'
|
|
elsif ch=EOF
|
|
or ch='\n' then
|
|
eof(s)
|
|
else
|
|
error(`unknown escape sequence \%c`, {ch})
|
|
end if
|
|
return ch
|
|
end function
|
|
|
|
function char_lit()
|
|
integer startch = ch,
|
|
res = next_ch() -- (skip opening quote, save res)
|
|
if ch=startch then
|
|
error("empty character constant")
|
|
elsif ch='\\' then
|
|
res = escape_char("character")
|
|
end if
|
|
ch = next_ch()
|
|
if ch=EOF
|
|
or ch='\n' then
|
|
eof("character")
|
|
elsif ch!=startch then
|
|
error("multi-character constant")
|
|
end if
|
|
ch = next_ch()
|
|
return {tk_Integer, res}
|
|
end function
|
|
|
|
function string_lit()
|
|
integer startch = ch
|
|
string text = ""
|
|
while next_ch()!=startch do
|
|
if ch=EOF
|
|
or ch='\n' then
|
|
eof("string")
|
|
elsif ch='\\' then
|
|
ch = escape_char("string")
|
|
end if
|
|
text &= ch
|
|
end while
|
|
ch = next_ch()
|
|
return {tk_String, text}
|
|
end function
|
|
|
|
function get_op()
|
|
-- sequence operator = {ch}
|
|
string operator = ""&ch
|
|
ch = next_ch()
|
|
while charmap[ch]=OPERATOR
|
|
and find(operator&ch,operators) do
|
|
-- (^ ie/eg merge ">=", but not ");")
|
|
operator &= ch
|
|
ch = next_ch()
|
|
end while
|
|
integer k = find(operator,operators)
|
|
if k=0 then error("unknown operator") end if
|
|
return {opcodes[k], 0} -- (0 unused)
|
|
end function
|
|
|
|
function get_int()
|
|
integer i = 0
|
|
while charmap[ch]=DIGIT do
|
|
i = i*10 + (ch-'0')
|
|
ch = next_ch()
|
|
end while
|
|
if charmap[ch]=LETTER then
|
|
error("invalid number")
|
|
end if
|
|
return {tk_Integer, i}
|
|
end function
|
|
|
|
function get_ident()
|
|
string text = ""
|
|
while find(charmap[ch],{LETTER,DIGIT}) do
|
|
text &= ch
|
|
ch = next_ch()
|
|
end while
|
|
integer keyword = getd(text,KEYWORDS)
|
|
if keyword!=NULL then
|
|
return {keyword, 0} -- (0 unused)
|
|
end if
|
|
return {tk_Identifier, text}
|
|
end function
|
|
|
|
function get_token()
|
|
skipspacesandcomments()
|
|
tok_line = line
|
|
tok_col = col
|
|
switch ch do
|
|
case EOF then return {tk_EOI, 0} -- (0 unused)
|
|
case '\'' then return char_lit()
|
|
case '"' then return string_lit()
|
|
else
|
|
switch charmap[ch] do
|
|
case OPERATOR then return get_op()
|
|
case DIGIT then return get_int()
|
|
case LETTER then return get_ident()
|
|
else error("unrecognized character: (%d)", {ch})
|
|
end switch
|
|
end switch
|
|
end function
|
|
|
|
global function lex()
|
|
sequence toks = {}
|
|
integer tok = -1
|
|
object v
|
|
while tok!=tk_EOI do
|
|
{tok,v} = get_token()
|
|
toks = append(toks,{tok_line,tok_col,tok,v})
|
|
end while
|
|
return toks
|
|
end function
|