Hacker Newsnew | past | comments | ask | show | jobs | submit | haileys's commentslogin

The hardware was virtualized, it's even in the name for drivers on Win9x: Virtual Device Driver


VxD-s technically allowed virtualizing devices, but only in a very limited way. The port IO instructions were easily intercepted but not much else. VxDs could use page protection tricks to redirect MMIO but this was used sparingly.

Really the only serious "virtualization" was in the interrupt handling. Code in Win9x that handles interrupts had to be 16-bit and located in the lower 640kb of RAM.

Most VxDs worked like classic drivers, they encapsulated device-specific interfaces and provided more abstract application-level interfaces.


An O(n^2) parser is not fine for the mere reason that I don't know how one would make such a mess of the job in the first place.

A simple recursive-descent parser is easy to write by hand and runs in linear time.


> A simple recursive-descent parser is easy to write by hand and runs in linear time.

Recursive descenrs parsers are not linear.

They are generally O(n^2) and can even can go exponential with some grammars if written naively.

It can be pretty easy to do adverserival attacks on most naive descent parser and bring it to its knees.

Packrat parser [^1] are linear, but they are by no means "trivial 200 lines" type of parsers.

[^1]: https://arxiv.org/abs/cs/0603077


Recursive descent isnt guaranteed linear time

In the face of backtracking the time depends on the complexity of the grammar, since it's basically a brute force search through all the rules.


I think the point was that even if you managed to make a O(n*2) parser it will ve fast enough for human entered problems.


Not for C++ code generated by whole program optimizing compilers. Your "human entered" is doing the heavy lifting. Now that AI is writing code your assertion might be on shaky ground.


C++ can be slow to compile, but as I said, parsing is not the bottleneck. Even for really huge automatically generated C++ files, or old-school concatenated "unity builds", the parsing step is generally tiny compared to everything else.


> Not for C++ code generated by whole program optimizing compilers.

I'd be quite surprised if an optimizing compiler generated C++ code somewhere in its pipeline!


Take a look at Felix.

https://felix-lang.github.io/felix/

Ignore the 'scripting' language claim.


Oh, that is certainly not what I was expecting at all. I stand corrected!

I do have to wonder though - do you know what proportion of the C++ compiler time is spent parsing your generated C++ code vs. optimizing it?


Unfortunately no.

Felix is quite old at this point. It's a very interesting language, with many interesting ideas. It did not quite take off though.


What favorite feature(s) do you miss when working in other languages?


Coroutines, cooperative threading using fibres, type classes, generics, type deduction, easy interface with C++. The functional style, pattern matching. Flow based programming using 'chips and wires' abstraction.

It has many other interesting capabilities, for example, the ability to change its own grammar, that is rather too much, not for a pleb like me. It has unique (linear and affine) types too. It is really quite a handful.

Go did bring coroutines back into limelight but Felix predates Go by a margin.

Skaller, Felix's author, used Felix as a playground for novel language design ideas, so it was always in a state of flux.


Huh, that does sound like quite the grab bag of features. Think I'll have to find time to further investigate. Thanks for taking the time to elaborate!


https://felix-tutorial.readthedocs.io/en/latest/

This would be a good starting point. More in the manual.


C++26 reflection?


Oh, true! That's on me for not being specific enough. I was thinking about the optimization pipeline.


I thought it was funny that the author used a variety of OCR tools with mixed success before spending a lot of time manually fixing up the output from the best one, rather than just typing it in


That was also my thought… but I grew up mashing rubber keys for hours copying “games” out of magazines and books! Then hours after fixing all the typos!


I spent hours typing 6502 assembly. It went a lot better when someone dictated: LDA, STA, BEQ, LDY, STY...


I ran it through paddle paddle OCR and it flawlessly did it. Google's OCR through my phone's Google lens had also worked at getting a very good extraction but not 100% correct. Definitely would spend less time fixing it than hand copying.

IDK what the author was using but I feel like he could have shared how his OCR attempt went, but I am thinking he tried some naive OCR tools.


Author here - that's a good idea actually, it shouldn't be too hard to compare the various attempts. The tools I used were whatever my Android built-in is (likely Google Gemini, but I can't tell whether this is something Samsung has replaced in OneUI); tesseract; tesseract with various tweaks and charsrt restrictions; Claude; and finally, manual fixes based on disagreements between all the previous.


Took me almost 2 minutes for 4 lines (and I missed a character in one of them!). I would opt for OCR too, obviously so I'm prepared for the next bash t-shirt I'd come across...


I think this is a case where two people can successfully complete the task manually faster than one attempting to automate it. Get a ruler, read five centimetres of characters to your colleague, have them type it in as you go, then repeat that five centimetres back to you. Correct as you go. Format your string with the same line-breaks as the t-shirt, and remove them at the end, so you can be sure you've got the correct length on each row. Trial-and-error adjust the five-cm distance depending on your success rate as you go along

All in, you should have a non-corrupted string in 10-15 min.


Feels like my experienced reality of task automation in corporate environments. We routinely have engineers spend 40+ hours automating tasks that an entry level person can do manually in 10 minutes and only need to be done weekly. Automation at all costs seems to be the future


It’s certainly not a new phenomenon. I appreciate this XKCD [1], with a chart of “How long can you work on making a routine task more efficient before you’re spending more time than you save”

It’s not the final word, since automation has other benefits: documenting the procedure’s steps, reducing human errors, increasing consistency, etc.

1: https://xkcd.com/1205/


"just typing it" would be more error prone for the average human


Not really. Transcribing long sequences of nonsense is annoying but quite easy to do without error as long you're patient enough to follow a simple process of reading, typing, and double-checking character-by-character.


Gemini3.5 Flash didn't have a problem OCR'ing and base64 decoding it, despite the OCR step having errors, it just fixed them in the base64 decoding step.


(Author here) Yes I agree. It was a fun side-quest though. Reminds me of https://xkcd.com/1205/


I'm guilty of this, but for me this kind of thing is optimizing over annoyance rather than time.


> DOS barely has any concept of processes

That's not true - DOS lacks multitasking but it absolutely has a concept of processes. They're called PSPs (program segment prefixes, a struct containing data about that process) and the OS has a range of syscalls to manage them. Any program can spawn a child program and wait for its completion.

The memory allocation syscalls track which program owns each dynamically allocated block of memory (the block has a header which points to the PSP), and frees the blocks allocated by a program when it exits. The filesystem syscalls deal with file handles opened by processes in just the same way.

The famous "terminate and stay resident" syscall causes a program to exit and return to its parent process while keeping its PSP and dynamically allocated memory blocks intact.

16 bit Windows introduced multitasking but reused DOS's PSP based process model and would allocate a PSP for each Windows task, switching the current DOS PSP when switching between Windows tasks.


Yes it's a riff on WSL. It wouldn't make sense to flip the naming around - people would then just be confused about the naming in the other direction.


It was mostly in jest, but consistency would be nice - even if WSL makes no sense.


> I'm not saying Windows 9x in particular had anything super interesting going on.

Oh it did though, it is a very interesting OS. Much more interesting than it usually gets credit for.

It's a proper 32 bit OS with pre-emptive multitasking and demand paging that is enough of a chimera with DOS that it still supports DOS programs, 16 bit Windows apps, and even your old DOS drivers - side-by-side with all the new 32 bit stuff.


The premise is incorrect and ignorant of the history - this is sticky sessions and the idea has been around longer than 20 years.

The "cloud native" (as the author refers to it) idea that app servers should be stateless is actually the new idea.

The industry eventually reached consensus on sticky sessions being a bad idea a lot of the time. That's why stateless app servers became the norm.


This is correct. Win9x did have memory protection, it just made an intentional choice to set up wide open mappings for compatibility reasons.

WSL9x uses the same Win9x memory protection APIs to set up the mappings for Linux processes, and the memory protection in this context is solid. The difference is simply that there is no need to subvert it for compatibility.


I obtained the DDK from WinWorld: https://winworldpc.com/product/windows-sdk-ddk/windows-95-dd...

It's got lots of very thorough documentation and sample code to dig through


Well it did take me 6 years to follow that up!


Can we get an official statement on which OS your project runs inside which OS? It's left slightly unclear, for the uninitiated!


doslinux is some tricky sleight of hand where it looks like Linux is running inside DOS, but it's actually the other way around (even though DOS boots first).

WSL9x takes quite a different approach. Windows boots first, but once Linux starts both kernels are running side-by-side in ring 0 with full privileges. They are supposed to cooperate, but if either crashes then both go down.


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

Search: