module 'emop.lexer' [Impl] { lex(Stream, Lexems) :- Impl:lex(Stream, Lexems). }, module Impl [Impl] { lex(Stream, Lexems) :- module Lexems [Stream, Lexems, Impl] { read(Lexem) :- Stream:position(Pb), ( Stream:read(C) -> true ), ( C = end_of_file -> Lexem = end_of_file(Pb) ; ( C = ' ' ; C = '\t' ; C = '\r' ) -> Lexems:read(Lexem) ; C = '\n' -> Lexem = end_of_line(Pb) ; C = '%' -> Lexems:read_line_comment(Comment), Stream:position(Pe), Lexem = comment(line, Comment, Pb, Pe) ; C = '/', Stream:read('*') -> ( Stream:read('*') -> Lexems:read_long_comment(Comment), Stream:position(Pe), Lexem = comment(doc, Comment, Pb, Pe) ; Lexems:read_long_comment(Comment), Stream:position(Pe), Lexem = comment(long, Comment, Pb, Pe) ) ; 'data.term':( C >= 'a', C =< 'z' ) -> Lexems:( read_ident_tail(C, Atom), read_atom_close(Atom, unescaped, Pb, Lexem) ) ; Impl:symbol_char(C) -> Lexems:read_symbol_tail(C, Atom), Stream:position(Pe), Lexem = atom(Atom, unescaped, Pb, Pe) ; ( C = ',' ; C = ';' ; C = '!' ) -> Stream:position(Pe), Lexem = atom(C, unescaped, Pb, Pe) ; ( 'data.term':( C >= 'A', C =< 'Z' ) ; C = '_' ) -> Lexems:read_ident_tail(C, Atom), Stream:position(Pe), Lexem = var(Atom, Pb, Pe) ; C = '0' -> ( Stream:read(C0), ( ( C0 = 'x' ; C0 = 'X' ) -> Lexems:read_hexa(Value) ; ( C0 = 'b' ; C0 = 'B' ) -> Lexems:read_binary(Value) ; C0 = '\'' -> Stream:read(C1), ( C1 = '\\' -> 'data.char':read_escape(Stream, ValueC) ; ValueC = C1 ), Value = 'data.char':code(ValueC) ; ( ( C0 = 'o' ; C0 = 'O' ) -> Stream:read(C1) ; 'data.char':decimal_digit(C0, _), C1 = C0 ) -> Lexems:read_octal(C1, Value) ) -> true ; Value = 0 ), Stream:position(Pe), Lexem = number(Value, Pb, Pe) ; 'data.char':decimal_digit(C, _) -> Lexems:read_decimal(C, Pb, Value), Stream:position(Pe), Lexem = number(Value, Pb, Pe) ; C = '\'' -> Lexems:read_quoted_string(C, Pb, String), 'data.string':atom(String, Atom), Lexems:read_atom_close(Atom, escaped, Pb, Lexem) ; C = '\"' -> Lexems:read_quoted_string(C, Pb, String), Stream:position(Pe), Lexem = string(String, Pb, Pe) ; ( C = '(' ; C = '[' ; C = '{' ) -> Stream:position(Pe), 'data.term':decomposition(Lexem, [C, Pb, Pe]) ; ( C = ')' ; C = ']' ; C = '}' ) -> Stream:position(Pe), Lexem = close(C, Pb, Pe) ; Stream:position(Pe), throw(error('Unknown char', file(Pb, Pe))) ). read_line_comment(Comment) :- module Accu [Stream] { get(C) :- ( Stream:read(C) -> C \= '\n' ). }, 'data.list':accumulate(Accu, String), 'data.string':atom(String, Comment). read_long_comment(Comment) :- module Accu [Accu, Stream] { skip_star :- Stream:read(C), ( ( C = ' ' ; C = '\t' ) -> Accu:skip_star ; C = '*', Stream:read(' ') ). get(C) :- ( Stream:read(C0) -> ( C0 = '*', Stream:read('/') -> fail ; C0 = '\n' -> ( Accu:skip_star -> C = ' ' ; C = ' ' ) ; C = C0 ) ). }, 'data.list':accumulate(Accu, String), 'data.string':atom(String, Comment). read_atom_close(Atom, Escaped, Pb, Lexem) :- Stream:position(Pe), ( Stream:read('(') -> Lexem = functor(Atom, Escaped, Pb, Pe) ; Lexem = atom(Atom, Escaped, Pb, Pe) ). read_ident_tail(C, Atom) :- module Accu_ident [Stream] { get(C) :- ( Stream:read(C), C \= 'end_of_file', 'data.term':( ( C >= 'a', C =< 'z' ; C >= 'A', C =< 'Z' ; C >= '0', C =< '9' ; C = '_' ) ) -> true ; fail ). }, 'data.list':accumulate(Accu_ident, T), 'data.string':atom([C | T], Atom). read_symbol_tail(C, Atom) :- module Accu_symbol [Stream, Impl] { get(C) :- ( Stream:read(C), Impl:symbol_char(C) -> true ). }, 'data.list':accumulate(Accu_symbol, T), 'data.string':atom([C | T], Atom). read_hexa(Value) :- module Aux [Stream] { read(V, R) :- ( 'data.char':hexadecimal_digit(Stream:read, V0) -> this:read('data.number':(V * 0x10 + V0), R) ; V = R ). }, Aux:read(0, Value). read_binary(Value) :- module Aux [Stream] { read(V, R) :- ( 'data.char':bit(Stream:read, V0) -> this:read('data.number':(V * 0b10 + V0), R) ; V = R ). }, Aux:read(0, Value). read_octal(C, Value) :- module Aux [Stream] { read(V, R) :- ( 'data.char':octal_digit(Stream:read, V0) -> this:read('data.number':(V * 0o10 + V0), R) ; V = R ). }, ( 'data.char':octal_digit(C, V0) -> Aux:read(V0, Value) ; Value = 0 ). read_decimal(C, Pb, Value) :- Lexems:read_tail_numeric(Tail_int_part), Int_part = [C | Tail_int_part], ( Stream:read('.'), Lexems:read_numeric(Float_part) -> true ; true ), ( Stream:read('e') -> ( Float_part = ['0'] -> true ; true ), ( Stream:read('-') -> ( Lexems:read_numeric(Tail_exp_part) -> Exp_part = ['-' | Tail_exp_part] ; Stream:position(Pe), throw( error('Ill-formed number', file(Pb, Pe)) ) ) ; Lexems:read_numeric(Exp_part) -> true ; Stream:position(Pe), throw( error('Ill-formed number', file(Pb, Pe)) ) ) ; Exp_part = ['0'] ), ( Float_part = [] -> 'data.string':number(Int_part, Value) ; 'data.list':append(Int_part, ['.' | Float_part], Partial), 'data.list':append(Partial, ['e' | Exp_part], String), 'data.string':number(String, Value) ). read_numeric(String) :- Stream:read(C0), 'data.char':decimal_digit(C0, _), String = [C0 | Tail], Lexems:read_tail_numeric(Tail). read_tail_numeric(String) :- module Accu_digit [Stream] { get(C) :- ( Stream:read(C), 'data.char':decimal_digit(C, _) -> true ). }, 'data.list':accumulate(Accu_digit, String). read_quoted_string(Delimiter, Pb, String) :- module Accu_string [Stream, Delimiter, Accu_string] { get(C) :- ( Stream:position(Pb), Stream:read(C0), ( C0 = Delimiter -> Stream:read(Delimiter), C = Delimiter ; C0 = '\\' -> ( Stream:read('\n') -> Accu_string:skip_space(C) ; 'data.char':read_escape(Stream, C) -> true ; Stream:position(Pe), throw( error('Ill-formed escape character', file(Pb, Pe)) ) ) ; C = C0 ) -> true ). skip_space(C) :- ( Stream:read(C0), ( C0 = ' ' ; C0 = '\t' ) -> Accu_string:skip_space(C) ; Accu_string:get(C) ). }, 'data.list':accumulate(Accu_string, String), ( Stream:read(Delimiter) -> true ; Stream:position(Pe), throw(error('Unterminated string', file(Pb, Pe))) ). }. symbol_char(C) :- ( ( C = ':' ; C = '+' ; C = '-' ; C = '*' ; C = '/' ; C = '\\' ; C = '=' ; C = '<' ; C = '>' ; C = '|' ; C = '.' ) -> true ; fail ). }