Current section
Files
Jump to
Current section
Files
src/xdr_scan.erl
%% Copyright (c) 2000 Sendmail, Inc. All rights reserved.
%%
%% Scanner for XDR specifications
%%
-module(xdr_scan).
-export([file/1, string/1]).
-export([format_error/1]).
%% read file and return tokens
file(File) when is_atom(File) ->
file(atom_to_list(File));
file(File) when is_list(File) ->
case file:read_file(File) of
{ok, Bin} ->
scan(File, binary_to_list(Bin));
Error -> Error
end.
string(String) when is_list(String) ->
scan("", String).
scan(File, String) ->
case catch scan(String, [], 1) of
{ok, Tokens} -> Tokens;
{error, Description} ->
{Line, Message} = Description,
{error, {Line, File, Message}};
{'EXIT', Error} ->
io:format("xdr_scan: internal error : ~p~n", [Error]),
{error, {0, ?MODULE, "internal error"}}
end.
format_error(Message) ->
Message.
scan([$/,$* | Cs], Ts, Line) -> scan_comment(Cs, Ts, Line);
scan([$ | Cs], Ts, Line) -> scan(Cs, Ts, Line);
scan([$\t | Cs], Ts, Line) -> scan(Cs, Ts, Line);
scan([$\n | Cs], Ts, Line) -> scan(Cs, Ts, Line+1);
scan([C | Cs], Ts, Line) when C >= $A, C =< $Z ->
scan_identifier(Cs, [C], Ts, Line);
scan([C | Cs], Ts, Line) when C >= $a, C =< $z ->
scan_identifier(Cs, [C], Ts, Line);
scan([C | Cs], Ts, Line) when C >= $0, C =< $9 ->
scan_constant(Cs, 1, C-$0, Ts, Line);
scan([$-, C | Cs], Ts, Line) when C >= $0, C =< $9 ->
scan_constant(Cs, -1, C-$0, Ts, Line);
scan([C | Cs], Ts, Line) ->
case delimiter(C) of
false -> scan(Cs, [{C, Line} | Ts], Line);
Tok -> scan(Cs, [{Tok, Line} | Ts], Line)
end;
scan([], Ts, Line) ->
{ok, lists:reverse([{'$end', Line} | Ts])}.
%%
%% Comments
%%
scan_comment([$*,$/ | Cs], Ts, Line) ->
scan(Cs, Ts, Line);
scan_comment([$\n | Cs], Ts, Line) ->
scan_comment(Cs,Ts,Line+1);
scan_comment([_ | Cs], Ts, Line) ->
scan_comment(Cs, Ts, Line);
scan_comment([], Ts, Line) ->
throw({error, {Line, ?MODULE, "comment not terminated"}}).
%%
%% Identifiers
%%
scan_identifier([C | Cs], Acc, Ts, Line) when C >= $a, C =< $z ->
scan_identifier(Cs, [C|Acc], Ts, Line);
scan_identifier([C | Cs], Acc, Ts, Line) when C >= $A, C =< $Z ->
scan_identifier(Cs, [C|Acc], Ts, Line);
scan_identifier([C | Cs], Acc, Ts, Line) when C >= $0, C =< $9 ->
scan_identifier(Cs, [C|Acc], Ts, Line);
scan_identifier([$_ | Cs], Acc, Ts, Line) ->
scan_identifier(Cs, [$_|Acc], Ts, Line);
scan_identifier(Cs, Acc, Ts, Line) ->
case predefined(lists:reverse(Acc)) of
{true, Tok} -> scan(Cs, [{Tok, Line} | Ts], Line);
{false, Id} -> scan(Cs, [{identifier,Line,Id} | Ts], Line)
end.
%%
%% Constant values
%%
scan_constant([$x | Cs], Sign, 0, Ts, Line) ->
scan_hex(Cs, Sign, 0, Ts, Line);
scan_constant(Cs, Sign, 0, Ts, Line) ->
scan_oct(Cs, Sign, 0, Ts, Line);
scan_constant(Cs, Sign, N, Ts, Line) ->
scan_dec(Cs, Sign, N, Ts, Line).
scan_oct([C | Cs], Sign, N, Ts, Line) when C >= $0, C =< $7 ->
scan_oct(Cs, Sign, N*8 + (C - $0), Ts, Line);
scan_oct(Cs, Sign, N, Ts, Line) ->
scan(Cs, [{constant, Line, Sign * N} | Ts], Line).
scan_dec([C | Cs], Sign, N, Ts, Line) when C >= $0, C =< $9 ->
scan_dec(Cs, Sign, N*10 + (C - $0), Ts, Line);
scan_dec(Cs, Sign, N, Ts, Line) ->
scan(Cs, [{constant, Line, Sign * N} | Ts], Line).
scan_hex([C | Cs], Sign, N, Ts, Line) when C >= $0, C =< $9 ->
scan_hex(Cs, Sign, N*16 + (C - $0), Ts, Line);
scan_hex([C | Cs], Sign, N, Ts, Line) when C >= $A, C =< $F ->
scan_hex(Cs, Sign, N*16 + (C - $A) + 10, Ts, Line);
scan_hex([C | Cs], Sign, N, Ts, Line) when C >= $a, C =< $f ->
scan_hex(Cs, Sign, N*16 + (C - $a) + 10, Ts, Line);
scan_hex(Cs, Sign, N, Ts, Line) ->
scan(Cs, [{constant, Line, Sign * N} | Ts], Line).
predefined("int") -> {true,int};
predefined("string") -> {true,string};
predefined("opaque") -> {true,opaque};
predefined("void") -> {true, void};
predefined("float") -> {true,float};
predefined("double") -> {true,double};
predefined("hyper") -> {true,hyper};
predefined("bool") -> {true,bool};
predefined("unsigned") -> {true,unsigned};
predefined("enum") -> {true,enum};
predefined("struct") -> {true,struct};
predefined("union") -> {true,union};
predefined("case") -> {true,'case'};
predefined("default") -> {true,default};
predefined("typedef") -> {true,typedef};
predefined("switch") -> {true,switch};
predefined("const") -> {true, const};
predefined("program") -> {true, program};
predefined("version") -> {true, version};
predefined(Id) -> {false, Id}.
delimiter($[) -> '[';
delimiter($]) -> ']';
delimiter(${) -> '{';
delimiter($}) -> '}';
delimiter($() -> '(';
delimiter($)) -> ')';
delimiter($<) -> '<';
delimiter($>) -> '>';
delimiter($,) -> ',';
delimiter($;) -> ';';
delimiter($:) -> ':';
delimiter($*) -> '*';
delimiter($=) -> '=';
delimiter(_) -> false.