Hacker News new | past | comments | ask | show | jobs | submit | dbcurtis's comments login

This is past the NPRM stage, if I am reading correctly, so final rule is getting published in the federal register. That is as baked as regulations get.

But.... outlawing flatted 7th means no more mixolydian mode, so Appalachian and Cajun fiddlers will want to have words with you...

Prediction: Clear will now be free for state legislators, and the bill will be killed in committee.

it really is sad that i can actually believe this could be a realistic outcome.

No more adagios!! My kid would have loved that during violin lesson days. Kid, talking about a Handel sonata: "This is my favorite adagio movement." Teacher: "Why?" Kid: "It's only 5 measures long."

Eh.... any impact will play out over a long period of time. Everything interesting happens on the margin, so I do agree with you that CA's laws around non-competes has had a beneficial impact on new business formation, and contributed to CA's economic growth. If this gets fully implemented, it will level the playing field with other states, but it will take some time (a decade would be my bet) for the impact to be fully felt.

I tend to agree. Having done a bunch of DSL's over the years, and becoming extremely fluent with Bison+FLEX, I have to say that a hand-written LL parser with a couple of mutually recursive table-driving functions to parse expressions via precedence climbing is the way to go. Precedence climbing (or I think it is also called Pratt parsing?) is super simple and flexible. But the BIG bonus is in error reporting, and let's face it, most of the user interaction with your parser is with the error messages, otherwise it is push 'enter' and forget. Getting a reasonable error message out of an LR parser is about as much fun as poking yourself in the eye repeatedly with a sharp stick. With LL, you know what structure you are trying to build... with LR, you have to rummage around in parse stack looking for obscure clues.

I am aware this is an unpopular opinion, but I think the idea that recursive descent is inherently better suited to error reporting than table-driven LR is massively cargo-culted. You can handcraft error messages for an LR parser if you overspecify the grammar, meaning that you don't just write productions for the actual language; you also write productions for likely errors and have the predicates for those productions report your handcrafted error message.

I'm guessing that a lot of people's first impression of that will be "That's insane, are you seriously suggesting writing two grammars in one?" But that's exactly what you do when you build custom error reporting code into a recursive descent parser. It's just less obvious because the code is procedural instead of declarative.


I see the appeal of adding error nodes, but I'm not a huge fan. If you do this rather than either bombing out immediately on the first error or storing a stack of errors, then the syntax errors pollute the generated tree. This will require you to either add a separate pass for building a new tree that is the same as the old except without the error nodes, or you will have to handle syntax errors downstream in the analysis or code gen phase.

A recursive descent parser does not have to be procedural. I have written one in a functional language that I designed that has no mutable variables or loops (recursive functions handle both of these cases).

Parser generators are great for iterating on language syntax design. Once you know the language syntax, handwriting the parser should be easy. If it isn't, then it is most likely that either your language design or parsing skills need work. Both require time and practice.


> If you do this rather than either bombing out immediately on the first error or storing a stack of errors, then the syntax errors pollute the generated tree. This will require you to either add a separate pass for building a new tree that is the same as the old except without the error nodes, or you will have to handle syntax errors downstream in the analysis or code gen phase.

I don't see how this follows? There is no need to append an error node (or any node at all) to the AST when reducing an error production. You can just print an error message or push one onto a stack of error messages.

> Parser generators are great for iterating on language syntax design. Once you know the language syntax, handwriting the parser should be easy. If it isn't, then it is most likely that either your language design or parsing skills need work. Both require time and practice.

Parser generators aren't just for people who don't know how to write recursive descent parers; they are production ready tools. Python, Ruby, PHP, and Bash all use generated parsers.

I think the aversion to parser generators in general and LR parser generators in particular is a combination of not-invented-here-syndrome and cargo-culting the idea that LR parsers can't emit handcrafted error messages.


Yes, that’s also not uncommon for lexical grammars to haven token classes that are more general than what is actually valid, for example for numerical constants.

What would be useful is tooling that would check that one grammar is a sub-language of another grammar which is suitably connected (because in the general case that check is undecidable of course).


That's a very interesting way of looking at errors.

Wouldn’t the grammar of errors have to also be LR? Doesn’t that limit the kind of errors you can report?


Yes, it does have to be LR. Which can be a real PITA if you're working with a restrictive subset of LR, like LALR. But there are other options too. LR(1) is pretty powerful, and GLR even more so.

I utterly reject hand-written parsers. You give up the ability to trust your grammar - all too often you can accidentally add an ambiguity.

I like `bison --xml` for the fact that you can write your own code but trust the table.


Do you utterly reject essentially every mainstream language? Which languages do you use that do not use a handwritten parser?

Nor reentrant. In machines where the JSR that stores the return address at the jump target, usually interrupts are locked for 1 following instruction so that you have a chance to load the return address into the accumulator. Back in the day I worked with a RTOS on one of those beasties.


If you were an instruction pairing whiz, you could get pretty close to 2 IPC on the Pentium I for certain kernels.

The thing that Seymour had going for him at CDC is that he didn't bother with synchronous exceptions. On x86 (I worked on a late 486, Pentium I, Pentium II and Itanium II) you absolutely must have synchronous exceptions for backward compatibility. Debugging an exception on 6600 was a hair-tearing exercise, because the PC point somewhere near, not at, the instruction that raised, and there may be a swiss-cheese window of instructions that did not complete somewhere before that. Loads of fun for one and all. (I used 6600/7600's while working on Cyber 203/205 at CDC).


I'm pretty sure the 6600 could issue multiple instructions per clock. A 60 bit word could hold 4 15 bit instructions, or for instructions that required an 18 bit immediate address, those took two 15 bit parcels. If there were no conflicts, I think you could issue multiple instructions in a clock.

For instance, if Ax is the base address, and Bx is the stride, you could do A4 = A4 + B4 ; loading X4 by side-effect A3 = A3 + B3 ; loading X3 by side-effect X1 = X5 + X6 ; do an add of data loaded in the previous unroll of the loop A2 = A2 + B2 ; store X2 by side-effect, presumably computed in previous unroll

All 4 of those fit in one 60 bit word. And if you are clever with loop unrolling and instruction timing, you can get a lot of overlap.

The 6600 had dirt-simple opcodes that took about a week to memorize, but.... that was a long time ago, so sorry I can no longer assemble machine code in my head. Memory fading.....


Like many write-ups of the 6x00, it totally ignores the peripheral processor (PP) subsystem, which was both simple and innovative. The PP's were 10 independent processors, 12 bits wide, but with an 18 bit accumulator so that they could compute central memory addresses. Each had 4K of 12 bit words that stored both driver code and was used as I/O buffer. But.... there really were not 10, there was one copy of the PPU compute hardware, and 10 copies of the state that all the CDC old-timers referred to as "the PP barrel". It was just a big circular shift register, so the 10 PP's were actually just 10-way hardware multi-threaded. Yes, hardware multi-threading dates from 1957.

There famously were not interrupts in the classical sense in the 6x00, but PP's could read and scribble anywhere in central memory, and they could compute an address and jam it into the CPU's PC. So in effect infinitely flexible vectored interrupts.

4Kx12 is not a lot of program space, so most I/O drivers consisted of one or more PP overlays that would be loaded depending on which I/O device was in use.

If I recall correctly, the operator console required a PP full time -- the console being a couple of CRT's with shared X & Y DACs, and independent Z DACs, so they used vector fonts for everything. A second PP was full time dedicated to scheduling the other 8, at least in the common operating systems. (There were a bunch of operating systems... but I won't get into that.)

Also... somebody (maybe Seymour himself?) worked out a 12 word boot loader... and PP0 had a switch panel of 144 toggle switches arranged in a 12x12 matrix. You could toggle in the bootloader once, and leave it forever. At boot time those 12 words were loaded into PP0 core.


Well for me it was a matter of how much time it took. I spent enough time understanding the Central Processor with all the weird CDC-specific terms. I had to reread several times before I realized Increment instructions did load/store. Oh, and that "bootloader" was called "dead start".

The peripheral processors were indeed a 10-way SMT thing, which they called a barrel processor. Each thread had three registers but they operated in really strange ways, and I just didn't figure that out.

There were other details like bandwidth being tied to bank count, which I also didn't go into.


For sure. I remember thinking.... "But where are the instructions to load and store X registers?" -- Psych! There aren't any! Just jam an address into a A register. Take that you RISC fan-boys, can you get to less than zero instructions?


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: