2016-12-03 11 views
0

Я построил REPL для языка в Эрланге. Я запустить его из командной строки, например:Оболочка внутри процесса Erlang печатает входные данные много раз

repl:main(Args). 

Она читает с помощью io_getchars, пока он не встречает ;, затем разбирает и lexes его:

getchar(eof) -> throw(eof); 
getchar([C]) -> C. 
getchar() -> getchar(io:get_chars("", 1)). 

read_term() -> 
    case getchar() of 
     $; -> ";"; 
     C -> [C|read_term()] 
    end. 

Это все хорошо, но взаимодействие с РЕПЛ выглядит следующим образом:

willow% erl -name MyName 
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false] 

Eshell V7.3 (abort with ^G) 
(MyName)1> repl:main(Args). 
Master is <0.39.0> in init_workers 
1> map(fn(x)=x+1, '[1 2 3 4 5]);  
ap(fn(x)=x+1, '[1 2 3 4 5]); 
p(fn(x)=x+1, '[1 2 3 4 5]); 
(fn(x)=x+1, '[1 2 3 4 5]); 
fn(x)=x+1, '[1 2 3 4 5]); 
n(x)=x+1, '[1 2 3 4 5]); 
(x)=x+1, '[1 2 3 4 5]); 
x)=x+1, '[1 2 3 4 5]); 
)=x+1, '[1 2 3 4 5]); 
=x+1, '[1 2 3 4 5]); 
x+1, '[1 2 3 4 5]); 
+1, '[1 2 3 4 5]); 
1, '[1 2 3 4 5]); 
, '[1 2 3 4 5]); 
'[1 2 3 4 5]); 
'[1 2 3 4 5]); 
[1 2 3 4 5]); 
1 2 3 4 5]); 
2 3 4 5]); 
2 3 4 5]); 
3 4 5]); 
3 4 5]); 
4 5]); 
4 5]); 
5]); 
5]); 
]); 
); 
; 
Delegated packet 0 
Delegated packet 1 
Delegated packet 2 
Delegated packet 3 
Delegated packet 4 
(2 3 4 5 6) 
2> 

Я также попытался:

read_term(Acc) -> 
    case io:request(standard_io, {get_until, '', scanner, token, [1]}) of 
     {ok, EndToken={';;', _}, _} -> AcC++ [EndToken]; 
     {ok, Token, _} -> read_term(AcC++ [Token]); 
     {error, token} -> {error, scanning_error}; 
     {eof, _} -> Acc 
    end. 

И, к сожалению, он имеет такой же эффект.

Я бы предпочел не видеть все возможные правые части струны, которые я ввел. Что вызывает это и как я могу остановить его?

EDIT: Если я запустил его как erl -noshell -eval 'repl:main()' из оболочки, эта печать не произойдет. Зачем?

+1

Вы забыли включить код? – Dogbert

+0

@Dogbert кричит, мой плохой - добавил. – tekknolagi

ответ

1

Вместо этого вы должны использовать io:get_line и перебирать полученную строку. Затем вам нужно решить, что делать, если полученная строка не содержит никаких символов;

, например:

1> Eval = fun(X) -> io:format("evaluation of ~p~n",[X]) end.            
#Fun<erl_eval.6.50752066> 
2> F = fun() -> 
     R = io:get_line("Enter a string : "), 
     L = string:tokens(R,";"), 
     [Eval(X) || X <- L] 
    end. 
#Fun<erl_eval.20.50752066> 
3> F().                         
Enter a string : map(fn(x)=x+1, '[1 2 3 4 5]);map(fn(x)=x+5, '[1 2 3 4 5]);uncomplete         
evaluation of " map(fn(x)=x+1, '[1 2 3 4 5])" 
evaluation of "map(fn(x)=x+5, '[1 2 3 4 5])" 
evaluation of "uncomplete\n" 
[ok,ok,ok] 
4> F().                 
Enter a string : map(fn(x)=x+1, '[1 2 3 4 5]);          
evaluation of " map(fn(x)=x+1, '[1 2 3 4 5])" 
evaluation of "\n" 
[ok,ok]  
5> 

[править]

io:get_chars/2 принимает число символов, приведенных в качестве параметра из входной оболочки 1, в вашем случае, и пусть все остальное. Оболочка не может знать, что вы снова вызовете функцию io:get_chars/2, чтобы она снова печатала остальную строку ввода, и она делает то же самое снова и снова при каждом вызове функции read_term/0, поэтому вы видите это странное поведение ,

io:get_line/2 принимает весь ввод от оболочки и возвращает его в строку (в erlang это список целых чисел), поэтому у вас есть чистое поведение в окне оболочки, тогда вам решать выбрать ваш любимый алгоритм для анализа этой строки. Я выбрал string:tokens/2, потому что я пытаюсь использовать библиотечные функции, когда они существуют, я думаю, что их легче читать и не нужна документация: o)

Если вы не хотите заботиться о некорректном вводе, вы может заменить функцию F/0 от

2> F = fun() ->        
2>  Rep = io:get_line("Enter a string : "), 
2>  [L,"\n"] = string:tokens(Rep,";"),  
2>  L 
2> end. 

и он будет делать то же самое, что ваш read_term/0 функция (за исключением удаляет последнюю $ ;, но он проверяет свое присутствие):

3> F().         
Enter a string : correct input; 
"correct input" 
4> F().   
Enter a string : missing semi colon 
** exception error: no match of right hand side value ["missing semi colon\n"] 
5> F().    
Enter a string : correct input; but extracharacters after semi colon 
** exception error: no match of right hand side value ["correct input"," but extracharacters after semi colon\n"] 
+0

Зачем мне нужно использовать 'io: get_line'? И это кажется сложнее, чем обработка символа символом или токеном с помощью токена. – tekknolagi