osdir.com
mailing list archive

Subject: Re: Fix for A=<<1>> - msg#00239

List: lang.erlang.general

Date: Prev Next Index Thread: Prev Next Index
You are of course right, but:

Sometimes I and many others do not use spaces to separate the symbols. The best example I can think of is:
Rec#rec{length=0,state=init,count=0,buf=<<>>}
where I do _not_ want spaces.

Size comparision of binaries I think is so uncommon that the programmer that thinks "A =< <<1>>" does not write "A=<<<1>>". It is to ambiguous to the eye. Especially size comparisions of binaries must be _very_ uncommon. The programmer that skips as many spaces between tokens as possible is begging for trouble.

Equality comparisions of binaries I think is also rather uncommon, but note that "A==<<1>>" is scanned correctly(tm) and "A==<1>>" gives an error since scanning of '==' is eager. Remains typing "A=<<<1>>" when meaning "A==<<1>>", but that is a double fault.

About the code comments: more precisely, which (kind of) comments need to be fixed?

About including the state in the fun: I guess more/6 could be change into something like:

more(Cs, Pos, State, Fun) ->
{more,{Cs,Pos,State,Fun}}.

And tokens/3 into:

tokens([], Chars, Pos) ->
tokens({[],Pos,io,
fun (Cs,P,State)->
scan(Cs, [], [] Pos, State})
end, Chars, Pos);
tokens({Cs,Pos,eof,_Fun}, eof, _) ->
{done,{eof,Pos},Cs};
tokens({Cs,Pos,_State,Fun}, eof, _) ->
Fun(Cs++eof, eof);
tokens({Cs,Pos,State,Fun}, Chars, _) ->
Fun(Cs++Chars, State).

note that Cs, Pos, State and Fun are still needed in tokens/3. The fun can only contain Stack, Tokens and Pos.


Then the calls to more/6 would have to change into:
scan(">"=Cs, Stack, Toks, Pos, State) ->
more(Cs, Pos, State, fun (C, S) ->
scan(C, Stack, Toks, Pos, S)
end);

And these calls are rather many so it will clutter the code compared to:

scan(">"=Cs, Stack, Toks, Pos, State) ->
more(Cs, Stack, Toks, Pos, State, fun scan/5);

By passing two (as far as I can see they are only 2: Stack and Tokens) unneseccary arguments to more/6 I can use the "fun scan/5" notation which improves readability.

Or did you have a smarter change in mind?

/ Raimo



Robert Virding wrote:
The problems are at different levels:

1. There is a fundamental difference in scanning atoms/strings and =<<<<<.
You have basically introduced infinite look-ahead (at least to the end of
the file) to try and determine what the first token actually is, for
everything else there is one character look-ahead. (As is the grammar which
is one LALR1)

2. There are at least three different "one key-press typos" which can give
"A=<<1>>":

A==<<1>>
A=<<<1>>
A= <<1>>

Two tests and a match. How can you so so certain what I meant as to choose
one? Introducing a match when I really meant a test will introduce a
fundamental semantic change to the code, both as to return value and to the
error case. Also if I had mistyped the variable name then this *really*
changes the meaning of the code. And it does it automagically, completely
silently and in a way which can make it extremely difficult for the
programmer to find!

3. Nothing should try to correct its input, especially not something as
fundamental as the scanner. Especially when the "correction" is not
unambiguous. Just because you now don't think the chances of meaning
something else is slim doesn't mean other people think the same way. Or that
you might not think so in the future. :-)

4. I personally always (or almost always) use spaces to separate my symbols
so I don't really see what the problem is.

My basic premise is that you can not add an "improver" which works silently
and is only sometimes correct. Will you take the responsibility when this
generates an serious, invisible error in someones code?

The trouble with writing code at this level is that you always have to try
and handle the case when users do things which you had assumed was so stupid
or strange,even though it is legal, that no one would do it, in this case
mean "A=<<<1>>" when they wrote "A=<<1>>". I remember that a relatively
early version of the JAM compiler could not handle the case when you did a
send as an argument to a function to get the message in as an argument,
(foo(X ! <big evaluation>, ...)). The premise was that send is used for side
effects not return values. Of course someone did just this and it crashed.

Robert

P.S. Liked the new code. You need to fix the comments. Can't the fun be
generated each suspend and include the state? I think it would make things
easier.






Was this page helpful?
Yes No
Thread at a glance:

Previous Message by Date: click to view message preview

Fw: erl_interface

Heil, Serge Aleynikov Got the code : =============== COMM_DRV.CC========================= #include <vector> using namespace std; #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <errno.h> #ifndef WIN32 #include <termios.h> #endif #include <unistd.h> extern "C"{ #include "erl_eterm.h" #include "erl_format.h" #include "erl_marshal.h" #include "erl_fix_alloc.h" #include "erl_malloc.h" #include "erl_rport.h" #include "erl_connect.h" #include "erl_start.h" #include "erl_resolve.h" extern void erl_init_nothreads(void *x, long y); #define erl_init(x,y) erl_init_nothreads(x,y) } #include <ei.h> #pragma pack(1) #include <erl_driver.h> #include "comm_drv.h" typedef ETERM * PETERM; static void hex_dump(char * buff,int len); HPORT openport(char * name,int speed) { if(!name) { #ifdef WIN32 return INVALID_HANDLE_VALUE; #else return -1; #endif } #ifdef WIN32 //WIN32 platform COMMTIMEOUTS t_outs; COMMCONFIG cfg; DWORD size; HANDLE porthandle=CreateFile(name,GENERIC_READ | GENERIC_WRITE,NULL,NULL, OPEN_EXISTING,NULL,NULL); if(porthandle==INVALID_HANDLE_VALUE || !GetCommConfig(porthandle,&cfg,&size)) { return INVALID_HANDLE_VALUE; } t_outs.ReadIntervalTimeout=1; t_outs.ReadTotalTimeoutMultiplier=1; t_outs.ReadTotalTimeoutConstant=1; t_outs.WriteTotalTimeoutMultiplier=1; t_outs.WriteTotalTimeoutConstant=1; cfg.dcb.BaudRate=speed; cfg.dcb.Parity=NOPARITY; cfg.dcb.StopBits=ONESTOPBIT; cfg.dcb.ByteSize=8; if(!SetCommConfig(porthandle,&cfg,cfg.dwSize) || !SetCommTimeouts(porthandle,&t_outs)) { return INVALID_HANDLE_VALUE; } return porthandle; #else //UNIX (posix) platform int ispeed; int porthandle; switch(speed) { case 115200: ispeed=B115200; break; case 57600: ispeed=B57600; break; case 38400: ispeed=B38400; break; case 19200: ispeed=B19200; break; case 9600: ispeed=B9600; break; case 4800: ispeed=B4800; break; case 2400: ispeed=B2400; break; case 1200: ispeed=B1200; break; case 600: ispeed=B600; break; case 300: ispeed=B300; break; default: return -1; } termios Settings; porthandle=::open(name,O_RDWR | O_NONBLOCK | O_NOCTTY); if(porthandle == -1) { return -1; } tcgetattr(porthandle, &Settings); cfmakeraw(&Settings); Settings.c_cflag = (CS8 | CREAD | CLOCAL | ispeed); Settings.c_lflag =0; //Settings.c_iflag = (IGNCR | IGNBRK | IGNPAR); Settings.c_iflag = (IGNBRK | IGNPAR); Settings.c_iflag &= ~INPCK; tcflush(porthandle,TCIOFLUSH); if(tcsetattr(porthandle, TCSANOW, &Settings) ==-1) { return -1; } return porthandle; #endif }; void closeport(HPORT porthandle) { #ifdef WIN32 if(porthandle!=INVALID_HANDLE_VALUE)CloseHandle(porthandle); #else if(porthandle != -1)close(porthandle); #endif } bool writeport(HPORT port,char * buff,int size) { int rc; if(size == 0)return true; #ifdef WIN32 WriteFile(port,buff,size,(DWORD *)&rc,NULL); #else rc=::write(port,buff,size); #endif //printf("\noutwrite:%u",rc); if(rc==size)return true; if(rc == 0)return false; if(rc < 0) { if(errno == EAGAIN || errno == EINTR)return false; return false; } }; void commstep(HPORT port,ErlDrvPort dport) { char buff[512]; int rc; #ifdef WIN32 if(port ==INVALID_HANDLE_VALUE)return; bool rc2=ReadFile(port,buff,sizeof(buff),(DWORD *)&rc,NULL); #else if(port == -1)return -1; rc=::read(port,buff,sizeof(buff)); #endif if(rc == 0)return; if(rc < 0) { if(errno == EAGAIN || errno == EINTR)return; return; } int n=2; ETERM ** termlist=(ETERM **)new (ETERM *)[n]; ETERM * term_int=erl_mk_int(COMM_READ); ETERM * term_bin=erl_mk_binary(buff,rc); termlist[0]=term_int; termlist[1]=term_bin; ETERM * term2=erl_mk_list(termlist,n); int outsize=erl_term_len(term2); unsigned char * outbuff=new unsigned char[outsize]; erl_encode(term2,outbuff); driver_output(dport,(char *)outbuff,outsize); erl_free_term(term2); erl_free_term(term_int); erl_free_term(term_bin); delete[] termlist; }; #pragma pack() static void hex_dump(char * buff,int len) { for(int i1=0;i1 < len;i1++) { char c1=buff[i1]; printf("%2x(%c)",c1,(isprint(c1))?c1:' '); } printf("\n"); }; void send_int(ErlDrvPort port,int arg) { ETERM * term=erl_mk_int(arg); int size=erl_term_len(term); unsigned char * buff=new unsigned char[size]; erl_encode(term,buff); driver_output(port,(char *)buff,size); delete[] buff; erl_free_term(term); }; typedef struct { ErlDrvPort port; HPORT porthandle; } comm_data; static ErlDrvData comm_drv_start(ErlDrvPort port, char *buff) { erl_init(NULL,0); comm_data* d = (comm_data*)driver_alloc(sizeof(comm_data)); d->port = port; return (ErlDrvData)d; } static void comm_drv_stop(ErlDrvData handle) { driver_free((char*)handle); } static void comm_drv_output(ErlDrvData handle, char *buff, int bufflen) { ETERM * term1; ETERM * tport; ETERM * tspd; char * portname; int spd; ETERM * tbuff; ETERM * tsize; char * buff2; int size2; unsigned char * outbuff; int outsize; comm_data* d = (comm_data*)handle; char fn = buff[0], arg = buff[1], res; switch(fn) { case COMM_OPEN: term1=erl_decode((unsigned char *)buff+1); ((unsigned char *)term1)); tport=erl_element(1,term1); tspd=erl_element(2,term1); portname=erl_iolist_to_string(tport); spd=ERL_INT_VALUE(tspd); d->porthandle=openport(portname,spd); erl_free(portname); erl_free_term(tspd); erl_free_term(tport); erl_free_term(term1); res=(d->porthandle > 0)?1:0; driver_output(d->port, &res, 1); break; case COMM_CLOSE: closeport(d->porthandle); res=1; driver_output(d->port, &res, 1); break; case COMM_STEP: commstep(d->porthandle,d->port); break; case COMM_WRITE: tbuff=erl_decode((unsigned char *)buff+1); buff2=(char *)ERL_BIN_PTR(tbuff); size2=ERL_BIN_SIZE(tbuff); res=(writeport(d->porthandle,buff2,size2))?1:0; erl_free_term(tbuff); driver_output(d->port, &res, 1); break; default: res=0; driver_output(d->port, &res, 1); break; }; } ErlDrvEntry comm_driver_entry = { NULL, /* F_PTR init, N/A */ comm_drv_start, /* L_PTR start, called when port is opened */ comm_drv_stop, /* F_PTR stop, called when port is closed */ comm_drv_output, /* F_PTR output, called when erlang has sent */ NULL, /* F_PTR ready_input, called when input descriptor ready */ NULL, /* F_PTR ready_output, called when output descriptor ready */ "comm_drv", /* char *driver_name, the argument to open_port */ NULL, /* F_PTR finish, called when unloaded */ NULL, /* F_PTR control, port_command callback */ NULL, /* F_PTR timeout, reserved */ NULL /* F_PTR outputv, reserved */ }; extern "C"{ DRIVER_INIT(comm_drv) /* must match name in driver_entry */ { return &comm_driver_entry; } } ==================COMM_DRV.H==================== #ifndef __erlint_h__ #define __erlint_h__ #include <erl_driver.h> #define COMM_OPEN 1 #define COMM_CLOSE 2 #define COMM_STEP 3 #define COMM_READ 4 #define COMM_WRITE 5 #define COMM_DATA 6 #define COMM_ERROR 7 #ifdef WIN32 #include <windows.h> typedef HANDLE HPORT; #else typedef int HPORT; #endif HPORT openport(char * name,int speed); void closeport(HPORT port); bool writeport(HPORT port,char * buff,int size); void commstep(HPORT port,ErlDrvPort dport); #endif =================COMM.HRL==================== -define(COMM_OPEN,1). -define(COMM_CLOSE,2). -define(COMM_STEP,3). -define(COMM_READ,4). -define(COMM_WRITE,5). ==================COMM.ERL======================= -module(comm). -export([start/2,stop/1]). -export([close/1,open/3,write/2]). -export([encode/1,init/3,loop/2]). -compile({inline,30}). -include("comm.hrl"). call_port(Pid,Msg) -> Pid ! {call, self(), Msg}, receive {Pid, Result} -> Result end. encode({comm_open,Name,Speed}) -> [?COMM_OPEN,term_to_binary({Name,Speed})]; encode({comm_close}) -> [?COMM_CLOSE]; encode({comm_step}) -> [?COMM_STEP]; encode({comm_write,Bin}) -> [?COMM_WRITE,term_to_binary(Bin)]. loop(Port,Client) -> receive % command interface to COMM_DRV {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive {Port, {data, Data}} -> Caller ! {self(), Data} end, loop(Port,Client); % periodic poll serial driver {comm_step,Delay} -> Port ! {self(), {command, [?COMM_STEP]}}, timer:send_after(Delay,self(),{comm_step,Delay}), loop(Port,Client); % data from serial driver {Port,{data,List}}-> Bin1=list_to_binary(List), case binary_to_term(Bin1) of [?COMM_READ,Bin2]-> case catch Client ! {?COMM_READ,Bin2} of {'EXIT',Reason}-> io:fwrite("~nCLIENT ~w invalid.~w",[Client,Reason]); _->ok end, io:fwrite("~nREAD:~w",[Bin2]); X -> io:fwrite("~nREAD?:~w",[X]) end, loop(Port,Client); {comm_read,Bin} -> io:fwrite("~nREAD:~w",[Bin]), loop(Port,Client); % stop the driver stop -> Port ! {self(), close}, receive {Port, closed} -> exit(normal) end; % abort in the C++ code {'EXIT', Port, Reason} -> io:fwrite("~nEXIT:~w ~n", [Reason]), exit(port_terminated); X-> io:fwrite("~nLOOP1:~w",[X]), loop(Port,Client) end. init(SharedLib,Client,Period) -> Port = open_port({spawn, SharedLib}, []), timer:send_after(Period,self(),{comm_step,Period}), loop(Port,Client). % load and started serial driver with pid Client and integer Period % Client - pid of receiver of data % Period - millisecond start(Client,Period) -> case erl_ddll:load_driver("./","comm_drv") of ok -> ok; {error, already_loaded} -> ok; {error,A} ->exit({error,A,"comm_drv"}) end, Pid=spawn(?MODULE, init, ["comm_drv",Client,Period]). %close serial port close(Pid) -> call_port(Pid,{comm_close}). % open serial port with Name and Speed % Name - string name of serial port % Speed - integer speed in baud open(Pid,Name,Speed) -> call_port(Pid,{comm_open,Name,Speed}). write(Pid,Bin) -> io:fwrite("~nERL:~w",[Bin]), call_port(Pid,{comm_write,Bin}). % stop and unload serial driver stop(Pid) -> Pid ! {call, self(), {comm_close}}, Pid ! stop, erl_ddll:unload_driver("comm_drv"). loop2() -> receive Data -> io:fwrite("~n~w",[Data]), loop2() end. start2() -> Pid=spawn(?MODULE,loop2,[]). > I wonder if someone could share erl_interface-based examples with me. > I've been trying to write some code that passes either a tuple/list, or > an integer from C to Erlang, and I am having a problem that in case of > integers (see iterate() and finalize() below) Erlangs gets a response > correctly, but in case of tuple/list (see initialize()), looks like > Erlang is waiting for something in addition to what the port replies. I > can see in debugger that the Port sends everything normally, and then > blocks on the read() function as expected. > > Serge

Next Message by Date: click to view message preview

Re: Web applications unification

On Wed, 28 May 2003, Mikael Karlsson wrote: >I guess a good starting point for such a framework would be >that one should implement the generic behaviour API then, >so that a supervisor can start the application or by using >application:start. If you have a runnable application, you need to write a start/2 function and define it in an .app file. In most cases, such a start function would call supervisor:start_link(), and while this is definitely recommended, it is no requirement. There are other ways to start an erlang node, e.g. using the -s flag and then calling application:start() (which assumes the existence of an .app file), or simply spawning processes. For a robust framework, we should definitely go with the OTP way of doing things, since it works well, and comes with both support and documentation. >If you provide a library with no processes, like xmerl, >then there is of course no need for this. Correct. >Then you have a choice of using builder and making .app, >.rel, .script and .boot files or using application:start in >your own code? If your applications do not have a start function, using builder will still give you the benefit of a start script, always picking the latest version of each application (if that's what you want, otherwise, a specific version of some app) and making sure they're in the path, and semi-automatic configuration of environment variables. /Uffe -- Ulf Wiger, Senior Specialist, / / / Architecture & Design of Carrier-Class Software / / / Strategic Product & System Management / / / Ericsson AB, Connectivity and Control Nodes

Previous Message by Thread: click to view message preview

Re: Fix for A=<<1>>

The problems are at different levels: 1. There is a fundamental difference in scanning atoms/strings and =<<<<<. You have basically introduced infinite look-ahead (at least to the end of the file) to try and determine what the first token actually is, for everything else there is one character look-ahead. (As is the grammar which is one LALR1) 2. There are at least three different "one key-press typos" which can give "A=<<1>>": A==<<1>> A=<<<1>> A= <<1>> Two tests and a match. How can you so so certain what I meant as to choose one? Introducing a match when I really meant a test will introduce a fundamental semantic change to the code, both as to return value and to the error case. Also if I had mistyped the variable name then this *really* changes the meaning of the code. And it does it automagically, completely silently and in a way which can make it extremely difficult for the programmer to find! 3. Nothing should try to correct its input, especially not something as fundamental as the scanner. Especially when the "correction" is not unambiguous. Just because you now don't think the chances of meaning something else is slim doesn't mean other people think the same way. Or that you might not think so in the future. :-) 4. I personally always (or almost always) use spaces to separate my symbols so I don't really see what the problem is. My basic premise is that you can not add an "improver" which works silently and is only sometimes correct. Will you take the responsibility when this generates an serious, invisible error in someones code? The trouble with writing code at this level is that you always have to try and handle the case when users do things which you had assumed was so stupid or strange,even though it is legal, that no one would do it, in this case mean "A=<<<1>>" when they wrote "A=<<1>>". I remember that a relatively early version of the JAM compiler could not handle the case when you did a send as an argument to a function to get the message in as an argument, (foo(X ! <big evaluation>, ...)). The premise was that send is used for side effects not return values. Of course someone did just this and it crashed. Robert P.S. Liked the new code. You need to fix the comments. Can't the fun be generated each suspend and include the state? I think it would make things easier.

Next Message by Thread: click to view message preview

Re: Fix for A=<<1>>

OK, your argument about the typo "A=<<<1>>" when meaning "A=<<1>>" i.e "A = << 1 >>" accidentally becoming a valid syntax "A =< << 1 >>" has convinced us to remove this change from erl_scan (at least for R9C). The debate will probably respawn (reflame) after the R9C release. It is easier to add later than to remove. The final word is certainly not said. / Raimo Niskanen, Erlang/OTP, Ericsson AB Robert Virding wrote: The problems are at different levels: 1. There is a fundamental difference in scanning atoms/strings and =<<<<<. You have basically introduced infinite look-ahead (at least to the end of the file) to try and determine what the first token actually is, for everything else there is one character look-ahead. (As is the grammar which is one LALR1) 2. There are at least three different "one key-press typos" which can give "A=<<1>>": A==<<1>> A=<<<1>> A= <<1>> Two tests and a match. How can you so so certain what I meant as to choose one? Introducing a match when I really meant a test will introduce a fundamental semantic change to the code, both as to return value and to the error case. Also if I had mistyped the variable name then this *really* changes the meaning of the code. And it does it automagically, completely silently and in a way which can make it extremely difficult for the programmer to find! 3. Nothing should try to correct its input, especially not something as fundamental as the scanner. Especially when the "correction" is not unambiguous. Just because you now don't think the chances of meaning something else is slim doesn't mean other people think the same way. Or that you might not think so in the future. :-) 4. I personally always (or almost always) use spaces to separate my symbols so I don't really see what the problem is. My basic premise is that you can not add an "improver" which works silently and is only sometimes correct. Will you take the responsibility when this generates an serious, invisible error in someones code? The trouble with writing code at this level is that you always have to try and handle the case when users do things which you had assumed was so stupid or strange,even though it is legal, that no one would do it, in this case mean "A=<<<1>>" when they wrote "A=<<1>>". I remember that a relatively early version of the JAM compiler could not handle the case when you did a send as an argument to a function to get the message in as an argument, (foo(X ! <big evaluation>, ...)). The premise was that send is used for side effects not return values. Of course someone did just this and it crashed. Robert P.S. Liked the new code. You need to fix the comments. Can't the fun be generated each suspend and include the state? I think it would make things easier.
Sign up for updates to this mailing list. email:
Loading Comments...
Home | News | Patents | Sitemap | FAQ | advertise

Advertising by