Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connectionsPath: ...!news.mixmin.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Bart Newsgroups: comp.lang.c Subject: Re: Top 10 most common hard skills listed on resumes... Date: Sat, 7 Sep 2024 11:53:32 +0100 Organization: A noiseless patient Spider Lines: 176 Message-ID: References: <875xrkxlgo.fsf@bsb.me.uk> <87o75bwlp8.fsf@bsb.me.uk> <871q27weeh.fsf@bsb.me.uk> <20240829083200.195@kylheku.com> <87v7zjuyd8.fsf@bsb.me.uk> <20240829084851.962@kylheku.com> <87mskvuxe9.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Sat, 07 Sep 2024 12:53:32 +0200 (CEST) Injection-Info: dont-email.me; posting-host="0a8001fc0483eb71abd00b3625106a2f"; logging-data="1431460"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/uBB7cj1xDPCgZv2Th5uOx" User-Agent: Mozilla Thunderbird Cancel-Lock: sha1:ye7E2QrgUNRK0VfnRi60HPcRnGY= Content-Language: en-GB In-Reply-To: Bytes: 7664 On 07/09/2024 02:44, Waldek Hebisch wrote: > Bart wrote: >> On 06/09/2024 11:19, Waldek Hebisch wrote: >>> Bart wrote: >> (You can balance it out by by requiring ASSIGN(&A, &B)!) > > This would not work in general, as I wrote it, the following are > valid: > > assign(&a, 42) > assign(&a, a + 1) > > but the second argument has no address, so your variant would not > work. I believe that C's compound literals can give a reference to a+1: #include void assign(int* lhs, int* rhs) { *lhs = *rhs; } int main(void) { int a=20; assign(&a, &(int){a+1}); printf("a = %d\n", a); } The output from this is 21. (You are not supposed to ask questions about how assign() can be implemented if assignment statement is not available. Here I'm just showing the symmetry at call-site and in callee.) > You can use stack machines to get reasonably simple definition of > semantics. But still slightly more complex than what I outlined > above. And code for stack machines is unpleasent to optimize. > In a compiler for a language where official semantics is stack > based the first things that compiler does is to track few items > on top of the stack and match them to sequences like > > push a > push b > call op > > Once sequence is matched it is replaced by corresonding operation > on variables. If this matching works well you get conventional > (non-stack) intermediate representaion and reasonably good code. > If matching fails, the resulting object code wastes time on stack > operations. (My stack IL is different. The stack is a compile-time stack only, and code is scanned linearly during code-generation. Roughly, the 'stack' corresponds to the machine's register-file, although in practice register allocation is ad-hoc. In my current scheme, the hardware stack is rarely used except for function calls. You might notice I use Load/Store rather than Push/Pop, this was to avoid confusion with hardware push/pop instructions. When A and B are in registers, then A=B results in a register-register move.) > > Of course, if you don not minds slowdowns due to stack use, then > stack machine leads to very simple implemantaion. I use a software stack for interpreted code. > Best Forth compilers > have sophisticated code to track stack use and replace it by > use of registers. Other Forth compilers just accept slowness. Then you no longer have a language which can be implemented in a few KB. You might as well use a real with with proper data types, and not have the stack exposed in the language. Forth code can be very cryptic because of that. My IL stack code is typically easier to follow than Forth, and would be easier to write, if still a slog. (That's why I use a HLL!) >> Obviously, you can have RHS terms that cannot appear on the left, like >> '42', but that's usually due to separate constraints of the language. > > Well, logically you can not change value of a number, so you can > not assign to a number, that is very fundamental. But it's not prohibited by the grammar. > You could > try to define > > x + 1 = y > > as solving equation for x, that quickly runs into trouble due to > equations which are no solutions or multiple solutions. (Actually, 'x + 1 = y' is well defined in my languages. But that's because '=' means equality. The result is true/false.) >> Why don't you need to compute the address of B? > > Well, B may have no address. In case when B is variable computing > its address is part of computation of its value. In general, > computing value of B need computing addresses of all variables > contained in B. > >> Why don't you need to >> load the value of B? > > "compute value" means putting result in place which is available > to subsequent operations, so logically no extra load is needed. If you look typical generated code, then 'compute value' can often require discrete loads. But sometimes it is implicit: add R, [b] However, so is Store sometimes: add [a], R > And for variables "compute value" includes loading them. > >> It is more like this: >> >> compute address of B >> load value of B via that address to some temporary location >> compute address of A >> store new value of A via that address > > The point is that last part (that is store instruction) logically > does not change when you vary A and B. Only this part corresponds to > assignment. The first to lines logically form a whole, that > is "compute B". And when you vary B you may get quite different split > of "compute B" into part. Moreover, logically "compute value of B" > and "compute address of A" are completely independent. Suppose you had a 2-address machine with this instruction: mov [a], [b] # right-to-left With a simple CPU, executing it might involve: * Getting the address of b from the instruction into the address register * Performing a memory read access to load b into a register * Getting the address of a from the instruction into the address register * Performing a memory write access to write the register to a >> (c ? a : b) = (c ? a : b); > > As noticed, people prefer symmetric notation, so most languages > make it "symmetric looking". But if you dig deeper there is > fundametal asymetry. What started the subthread was the question of which HLL goes between ASM and C (since someone suggested that C was mid-level). People suggested ones like BLISS and Forth. I remarked that a proper HLL would let you write just A to either read the value of variable A, or write to it. Eg. A = A, without special operators to dereference A's address. At the lower level it might be push/pop, load/store, or even *&A = *&A, ========== REMAINDER OF ARTICLE TRUNCATED ==========