Coder Social home page Coder Social logo

skx / foth Goto Github PK

View Code? Open in Web Editor NEW
73.0 3.0 5.0 1.3 MB

Tutorial-style FORTH implementation written in golang

License: GNU General Public License v2.0

Go 95.31% Forth 4.69%
forth golang scripting-language interpreter go forth-like tutorial tutorial-code

foth's Introduction

Steve Kemp

  • I've been programming for over half my life, I'm comfortable creating, developing, maintaining, and improving software written in C, C++, Emacs Lisp, Perl, Ruby, Java, Shell, TCL, etc.
    • Most of my new projects are written in Golang.
    • But also I've been writing code in Z80 assembly language, to run under CP/M and the humble ZX Spectrum 48k.
  • My interests primarily revolve around compilers, interpreters, domain-specific languages, and virtual machines.
  • I'm also interested in retro programming/projects, primarily based around the Z80 processor.
  • Location: Helsinki, Finland.
  • Occupation: Sysadmin / Devops / Cloud-person.
    • I'm explicitly not a coder, nor a developer.

Surveys & Email Harvesting

I explicitly do not consent to receiving your "research surveys", or other contact generated via email scraping of the Github service. Such contact will always be followed up with.

Github Activity

foth's People

Contributors

skx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

foth's Issues

nested loops are broken

We use the stack, secretly, to implement do and while, for our loops.

This works (also in word-definitions):

10 0 do dup . loop

But the following fails:

10 0 do dup .  10 0 do dup .  loop loop

This is surprising since the stack should allow nesting properly, but still .. This should be fixed.

  • NOTE: Defining a loop in a word, then calling that in a loop works, which reinforces my point that the stack should be OK:
     > : foo 10 0 do dup 48 + emit loop cr ;
     > 10 0 do foo loop 
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789
     > 0123456789

Let caller set output writer

dump, emit, print, and string literals, etc get output via fmt.Printf.

We should allow these to go to a user-provided writer, this would also let us test output too.

Allow recursive definitions

Specifically for my toy benchmark I want to allow fibonacci calculation:

: factorial recursive  dup 1 >  if  dup 1 -  factorial *  then  ;

5 factorial .

I can hack this in, I'm sure. Currently compiling this fails to find the word "factorial" when compiling the section ".. 1 - factorial ..". Since we're compiling we can just fake this - once the compilation is complete we know it will be the last word compiled. So the index is just "len(existing words)". Right?

Set a "recursive" flag somewhere, when parsing the definition, and use that if parsing as a number fails.

part7 ?

Part seven comes after part six. To be hones I'm struggling to think of what to add.

We could declare part 7 as the final version:

  • comments?
  • else block for if?
  • strings?
  • case-insensitivity?
  • test-cases?

Implement part6 - with `if` and `then`.

This shouldn't be too different than the work that has already been done for do/while. The difference really is that we need a new "magic" code for a jump which is conditional.

If we assume:

if a > b { 
   bar
   baz 
}

Then it seems obvious we want to run a conditional and if the result is false we skip over the block. That's a logical way to handle things until we have to handle both "if and else".

Of course in FORTH terms that would be:

 x y > if bar baz then ;

Or:

 x y > if bar baz else something else then ;

Expand to add string support

I think this will be a new "chapter", then an update to the "final" foth/ directory.

The short version is that we should add two things:

  • Support for "memory".
  • Support for strings.

At the moment we have ." Foo " to represent a string-output, but if we instead said "Foo" was two actions:

  • Add the string to "memory".
  • Push the address of the string to the stack.

Then we gain a new thing, for example:

  • strlen
    • Read the address of the string from the top of the stack.
    • Push the length of the string to the stack.

We can add peek/poke instructions to refer to code, as well as a JUMP operation too if we want to allow self-modification and similar things.

It could be that we just allow interning, so that strings always return the same address, and they're not modifyable, but allowing 16k of "RAM" and a few primitives to operate upon it isn't a terrible compromise in the other direction.

I guess the real question is do we add a "next-string" word to define the address of where a string will go? Or do we just keep that internal/random/secret?

Add Reset method

If you get into a state where an error is raised it is possible that you're left with a broken repl.

Consider:

    > : foo 3 .;
    ERROR: 22 failed to convert .; to number strconv.ParseFloat: parsing ".;": invalid syntax
    > 4 .
    > 4 .
    > 4 .

Here the problem is that ".;" is missing a space, so the evaluator believes it is waiting for a ";" to terminate the word we're defining. But from our point of view we're back in the REPL.

If we implement Reset the caller, main.go, can call that after an error. While we don't want to trash the environment - and lose words the user has defined - we can certainly reset the compiling, defining and other appropriate flags.

Allow mutating words from within words

We currently can currently emulate (constant) variables by defining them as words:

 : now 3 ;

But they cannot be changed because recursive word-definitions fail to work as expected:

 : inc_now :now now 1 + ; ;
 : inc_now .
 4  -> Expected, but not seen

This fails because we always use the same scratch-space for defining words; allow this to work by using a stack which will let us recursively define words at runtime.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.