Path: csiph.com!eternal-september.org!feeder.eternal-september.org!aioe.org!.POSTED!not-for-mail From: "Rod Pemberton" Newsgroups: alt.os.development Subject: C parser ramblings, language design, etc Date: Fri, 11 Sep 2015 19:11:50 -0400 Organization: Aioe.org NNTP Server Lines: 107 Message-ID: NNTP-Posting-Host: n4wpt9zq8xR26Ttf9mo2BA.user.speranza.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: Opera Mail/12.16 (Linux) X-Notice: Filtered by postfilter v. 0.8.2 Xref: csiph.com alt.os.development:8747 You would think that C, being created long ago, would be very easy to parse with truly simple techniques, but things like optional braces, 'while' used as both 'while' and 'do-while', i.e., which 'while' goes with 'do' when nested, base types comprising multiple words, e.g., "long long", implicit int's, no keyword for typedef usage, conflict with implicit int's and typedef's, ... etc all complicate very simple C parsers. E.g., since braces are optional in C, there isn't much useful information for parsing, from statements like this: do while(x--); while(x--); That's confusing for a human and a simple parser. It could be recognized by both as either of these: do { while(x--); } while(x--); do {} while (x--); while(x--); Which 'while' goes with the 'do'? Only the first one is correct, but how do you determine that from the braceless syntax above? You get a 'while' prior to the 'while' you need. Technically, the second example needs a semicolon, but that doesn't help any with properly parsing the braceless example. 'while' is overloaded or ambiguous. It means two different things at different places, and somehow the parser or compiler must distinquish and keep track of which 'while' goes with which 'do'. Nesting can throw the dual-keyword do-while loop tracking out of whack. Adding nested while just complicates it further. You almost need a stack and a state-machine. That would've been much simpler to parse and emit code for if a different keyword was used at the bottom of the loop or if the condition was placed at the top of the loop for a do-while. I.e., this is much easier to parse, since the 'while' keyword isn't overloaded and it's easier to match paired 'do' and 'end': do end(x--); while(x--); do while(x--); end(x--); Now, you know that every end is at the same scope as the 'do' and you're not going to have "spurious" 'end's' inbetween. /* condition syntax at top of bottom test/exit loop */ do(x--); { while(x--); } That's even simpler. I think the goal for any language should not only be LALR(1) but also be able to be compiled in a single-pass with no backtracking and with exceptionally easy parsing. That's why my language uses space delimited parsing, like Forth, with character directed parsing. I.e., a character in front of each keyword, operator, etc in the language, tells the parser what is coming next. E.g., the hello world program for my language: ^main { $"Hello_World!" ~puts } I.e., '^' for declaring a procedure, '~' for calling a procedure, etc. The parser doesn't have to determine that "main" is a procedure or an identifier or that it's being declared here, or that "puts" is a procedure which is being called, or that "Hello_World" is a string, etc. The character directive tells it that. Save info. It's like a built-in AST, somewhat. I also went to a little bit of extra work to support curly braces without following that pattern, which would've required something to follow a brace. Unfortunately, I just realized that I should've provided for a C style semicolon too ';' for multipled statements per block. I also did some work on my larger C parser project. I merged in a bunch of similar code from other projects which helped to fill the program out somewhat more than it was. Now, it emits nicely reformatted C, an AST as text, and it's emitting some very rudimentary assembly code, but it has a long, ... long way to go to properly compile C code. Fortunately, I have a number of other simpler C projects. I also recently made some great progress on my OS-like environment for DOS that provides a console window for DOS. It's coded for DJGPP (GCC) C and uses CWSDPMI features. I now just need to find some use for it. At the moment it doesn't provide any advantage over a standard DOS command line, except I can watch PM interrupts, which are only called by DJGPP apps, and install PM interrupts and keep them active. So, no RM interrupts are being monitored at the moment. The Windows 98/SE console windows was much faster than DOS. So, improving speed is one potential option for a purpose. Unfortunately, switching RM interrupts back to PM has overhead which could reduce any real gains from 32-bit PM C code. Unfortunately, CWSDPMI doesn't use v86, unless VCPI is installed, which would've reflected all RM interrupts to PM. Rod Pemberton -- Just how many texting and calendar apps does humanity need?