(series) how to design a programming language: even if youve never coded

the myth of the non-coder

 

the non-coder is a mythological beast, handed down from quaint old wives tales. people generally believe by age 10 that they are either a “computer person” or “not a computer person.” for an idea of what a computer person looks like, look up jack black as “computerman” on youtube.

the myth of the non-coder is reinforced by the myth of the coder. the coder is a person who was born understanding how to code, who has never heard of “hello, world” and who has never looked up a command more than once.

which isnt to say that coders and non-coders dont exist, but they exist almost entirely in mythology: made-up rules that are loosely based on reality.

a coder is someone who has coded. at least this is how it used to be. today, a coder is someone who has mastered coding! but this is another mythology; no matter how well you “master coding” there are more horizons and more things to learn.

perhaps you should hold off before telling people you are a “master coder.” but watch out for the many fanatics who will insist that until you are a master, that you are not a coder. from there, you could spend the rest of your life trying to prove something to people that arent paying attention.

the way i learned coding was typing examples out of a book, noting what they did, and learning the commands by comparing what happened to what i typed. i learned that print put words on the screen by typing in code that included the print command, and noting that it put words on the screen. you can also learn that print puts words on the screen by reading that it does that.

actually coding is a more interesting experience than just learning it from a book– although a book can help a lot. as you type in code, you go from noting what happens to predicting what you think will happen, to writing code that does what you want. though you still have to try it to be sure it does what you think it will– then repeat the process with changes and fixes.

 

 

a quick tour through beginner-friendly coding

1964: (dartmouth basic)

10 print “hello, world!”
20 goto 10

 

1967**: (logo)

forever [print “hello, world]

 

1986: (amigabasic)

while 1
print “hello, world!”
wend

 

1993: (lua)

while 1 do
print(“hello, world!”)
end

 

2005: (python)

while 1: print “hello, world!”

 

2015: (fig)

while
now “hello, world!” print
wend

 

** this is intended to be logo, which is from 1967, although there are over 300 dialects of logo. while it is easy to find a 1964 manual for basic, it is not as easy to find an authoritative source on what logo looked like in the 1960s. this line is correct microworlds logo:

forever [print “hello]

 

and it is presumed (but not certain) this would also work:

forever [print “hello, world!]

 

 

hour of make up your own code! (a challenge for every wordpress reader)

if youre on wordpress you may have heard of the “hour of code.” i think its a great idea, but if youre thinking of skipping it anyway, why not try the “hour of make up your own code?”

you dont even have to know how coding works to do it. but it could end up being your first step towards learning to code. still reading? ok, heres what you do:

 

1. imagine some things you could tell the computer to do.

 

2. give a name to each of these things you want to tell the computer to do. once you name it, that thing is a “command” for the computer. an example of a command is “uppercase.” it takes words and makes them uppercase– another is “dot.” it draws a dot on the computer, in any colour on any place on the screen.

 

3. (optional) for each command you make up, you can add “parameters.” parameters are details for the command. like for your “dot” command, you could have parameters for how many “dots” from the left side of the screen you want to put it, or how many “dots” from the top you want– or what colour you want to use. parameters look like this:

command parameter1 parameter2 parameter3

 

you can name your parameters if you want to:

dot: fromleft, fromtop, colour

 

4. (bonus) create as many “commands” as you want, then write a program in your new language!

1) dot: 5, 5, “orange”
2) line: 7, 10 – 30, 100 “green”
3) say-on-screen: “hello, this is my program.”

 

5. feel free to post your language ideas or your programs as a reply to this post, or put them on your own blog (or link to them here.) if you like the idea, feel free to copy this entire article to your own blog.

 

 

everyone should write a programming language

i know, it sounds completely bonkers. ive been toying with the notion for a year or two, and my original thinking on the matter was more of an ideal than a practical thing.

the first question is, “not everyone can write a programming language.” ok, thats not even a question.

not everyone can learn to code, either. wait, yes– everyone (that can learn to read) can learn to code. they might not be able to code in python, or java– but they can definitely code in something. theres absolutely no question. its a matter of making the language simple enough– and thats a hint.

why, why, why, should everyone write a programming language?

because its simply the best way to learn to code. its not the only way! its not always the easiest way– and if learning how to write a programming language isnt helping the student learn to code, then perhaps do something else.

but here i am, explaining to a good friend and fellow blogger who tells me im very good at explaining programming in plain english (thank you, its a huge compliment) that they dont even have to “learn” to code if they can write a programming language–

i know how crazy it sounds. and this is not the first but the second person ive said it to this week. im starting to think i could even be serious.

of course some people need help to learn how to code– and other people need help writing a programming language.

most people would need a lot of help writing a programming language– but then they wouldnt have to learn the language, get it? they would make it up, and thus skip the whole chore of learning it.

now that doesnt mean they would have it memorised– i still have to look up a command in the language i wrote myself, if im not using that command all the time. ive known most of those commands for more than year but hey, theres almost 100 of them. did i make this one with one parameter or two? oh, right, it had two.

what it means is if they made it up, they understand how it will work. steering them towards keeping it simple could be important, though in some cases it could be better to show them how to do things in a more sophisticated way. some people will find it worth the trouble, others will want an easy way (i sure did.)

if creating a language in python (source-to-source compiler or interpreter) i recommend implementing variables, i/o, simple math, loops, conditionals and functions– if its an interpreter you can put all of it in a loop, and have the exit command simply break the loop. that saves having to implement a real loop feature.

for a long time ive wanted to create a programming language designed to make it easy enough for anyone to create their own programming language.

python is the closest thing to that i know, but i mean something easier.

one of the reasons people dont know how easy it is to create a programming language, is that they start with a parser and try to make it sophisticated. as they teach at brown university– dont! start with functions. its what i did to create my language, and i found out its what they teach. you can add a parser later.

a parser can be simple. as they teach at brown, you can build an api and then have more than one parser for different styles of language. i did it that way because i wasnt trying to build a language first, and i didnt know i was going to. thats how easy it was, done that way– “what if i told you… that a language implementation could be written just like any other program?”

parser, scanner, lexer– cut that out! you need to loop through a string of text (possibly containing newlines) and do things based on what the text says. thats your “parser.” stop trying to make an enterprise-grade general purpose language as your first language, and youll have something to show for it a lot sooner.

people often say these days, you need something to accomplish if youre going to learn to code– an app, or a website. it isnt true! you can just practice little tiny snippets that are fun but dont do much thats useful. people learn that way sometimes.

but if youre looking for a thing to accomplish while learning how to code, try a language implementation! seriously– of a very simple language. you can do it! itll be fun. and it will take less time to learn how to code, because youll end up understanding how languages work before youve even learned your first. and yes, at this point i am completely serious.

 

 

debunking a lot of bunk: coding IS TOO “fun”

soon im going to take qz off my list of places with articles that make sense or check anything they say at all. (wait, have i done that already?)

i guess coding isnt “fun” anymore: https://qz.com/987170/coding-is-not-fun-its-technically-and-ethically-complex/

“ethically complex?” what the heck– i dont think theres anything inherently complex about creating a website, do you? when i was learning to code there was nothing about it that was ethically complex– im sure there are some aspects of publishing software that– could someone please help the author of this tripe get it together?

there are lots of pro-coding articles and a surprising number of anti-coding articles.

  • coding isnt as easy as they say (well its not always, it is certainly possible to make it difficult in some instances, isnt that a good thing?)
  • coding isnt for everyone (define “everyone” and why that isnt possible, please…)
  • coding shouldnt be taught in schools (fine, neither should math. what, i need to state a good reason and you dont?)

 

i have no idea where these people come from.

now when i was a kid and i learned coding, i used to think it made me special. today, im happy to tell you thats a lot of bunk– anyone can code if theyre interested. making it easy and making it interesting are a special challenge for anyone that wants to teach– but thats typical of teaching.

let me tell you something, those teachers that told you everyone needs math are lying. everyone benefits from math if they can do it, but not everyone needs it. it is possible to go through your life without it– just as you can with code. but making a special argument against teaching math in school would be absurd.

most people do not become mathematicians for a living, and most people who learn to code will not spend their lives as a career programmer. perhaps it takes a special kind of mind to code for a living– i dont recommend learning to code for that reason anyway. i recommend learning to code mostly because it will help you understand computers and technology better than people who dont learn to code. and thats a pretty solid argument.

if they tell you it cant be fun, or simply “isnt fun,” theyre lying. or theyre making an idiotic claim, which i will now address:

the article starts off with one of the worst non-factual claims that could possibly be made on the subject:

“the profile of a programmer’s mind is pretty uncommon.”

 

oh, great! taking us back 20 or more years in one fell swoop. thanks walt, youve just rejuvenated an urban legend people are working year after year to kill.

no, programmers dont have a special brain, they have a special skill. i remember a time that i couldnt whistle, but after hearing it explained enough different ways and practicing, i managed (years later.) perhaps that part of my brain finally developed? no! i just learned how to whistle. coding is no different.

the reason i know its no different is because ive done experiments (limited in scope for sure) to teach code concepts to all sorts of people. the thing is, code can be over-complicated. but those over-complications are not requirements that cant be mitigated. because of useful abstractions, almost nothing in code is ACTUALLY required. it varies depending on the task. it can be both fun, and simple, and still powerful.

its really just language. and no one is telling you that it takes a special person to write a sentence. nope, literacy touches every group of people except (and often including) those who are extremely poor and didnt have the best advantages in their youth.

practically anyone can learn to read. if theres an exception, its a true exception– if you can learn to read, you CAN learn to code. but like with reading, how easy it is depends on both the teacher and the lesson. if you have an awful teacher and start with a hard lesson, only some people will manage. that should be obvious, and doesnt prove that learning anything is difficult or “no fun.”

i suck at math, so you know. learning code actually helped me with math a little, though some people will probably tell you that you need to be good at math to code. nope! i needed to learn to code first.

more tripe:

 

” As well as being highly analytical and creative, software developers need almost superhuman focus to manage the complexity of their tasks. Manic attention to detail is a must; slovenliness is verboten.”

so if youve been diagnosed with a.d.d., i guess that counts you out! well, i WAS diagnosed with a.d.d. and even treated for it, but not until id been coding for ten years. i guess all that coding didnt help me focus much– even though its a requirement!

so first they tell you that you have to be a special kind of person, and now weve raised that to be “almost superhuman!” theres more than enough data in these first two claims for the laziest of armchair scientists to debunk the article, but im going to do more of that work for you:

 

“…a quasi-symbiotic relationship between human and machine that improves performance and motivation.”

if i managed a publication that an author on my payroll submitted this to, id be asking for a urine test right about now. this author is high.

 

” When it comes to programming, why do policymakers and technologists pretend otherwise?”

i dont know buddy, its probably for the same reason they pretend that the earth isnt flat, or that the moon landing actually happened.

however, in the second half the article the author nearly admits (just not explicitly) that all that leaning on costly prejudices was more or less click-bait: it was a segue into the importance of the ethics and politics of technology:

 

“In an ever-more intricate and connected world, where software plays a larger and larger role in everyday life, it’s irresponsible to speak of coding as a lightweight activity.”

no it isnt. it it certainly CAN BE a lightweight activity, like playing with legos or scultping with clay. and you can also segue from throwing play-doh at the floor to the ethics of artistic expression, the politics of copyright and the history of propaganda, but sometimes a cigar is just a freaking cigar.

by the time the author admits what hes really saying, his article has done more damage than it makes up for. heres my advice: dont reinforce a load of nonsense to throw in a good point at the end of an article. it shouldve been an article about the negative impact of click-bait on journalism, though its too late for that. heck, if thats what passes for journalism now, i could write for qz and im not even trying. (dont call me, guys, ill call you.)

 

 

thanks to mhneifer for pointing this article out in the first place: https://f7l8c9.wordpress.com/2017/05/25/coding-is-not-fun/

 

ive never cared much for syntax highlighting

code-1839406_960_720

 

syntax highlighting is meant to make it easier to read and manage code. its not intended as training wheels, but a tool for professionals and students alike.

i find it draws attention away– if only a small amount of it– from what im trying to do. there are also at least two problems with syntax highlighting, regarding the colours chosen: first, that the parts of syntax that need the brightest or most vibrant colours (that draw the most attention) follow the same logic for everyone. just for a random example, in the picture above the items in red– a colour used for “stop” and “warning” because it gets the most attention– are the tag names, and the equals sign. a more useful scheme to me would be if = was one colour, and == was a different colour (to make assignment vs comparison easier to spot.)

its different for every person. i dont need the tag names in red– theyre already marked with a chevron to the left. thats what im looking for to find tag names. yes, red certainly makes it easier to find the tags (or equals signs) but the whole time im coding, those tags now try to pull me away from the rest of the code. its not worth the tradeoff.

the other problem with colours chosen is that at any given time, what im really looking for in code is a specific group of things, and it changes based on context. so while im looking for whatever it is that im looking for, (it might not even be syntax) ive got all this colourful noise in the text im searching through. now picture a needle in a haystack: do you want to look for that silver needle in a bale of ordinary blonde hay, or would it be easier if the hay were eight or nine different colours?

i find highlighting very useful for search results– especially multiple results displayed at once:

leafpad

 

but i only use the search feature if a quick look over the page doesnt suffice, and syntax highlighting only gets the way.

im inclined to think that syntax highlighting is something a lot of people just “put up with” because its there, and its “too much bother” to turn off. (most people hate configuring anything in general, unless they need to and they cant.) and im sure its useful at least for most of the people that make it a feature in the editors theyre writing. it would be funny if that werent the case– if everyone thought that everyone else preferred highlighting, so developers that didnt want or need it assumed they had to add it for the users, while users assumed there was benefit (because why else have the feature?)

its even possible that syntax highlighting is a fad, but im sure a lot of people either love it, or think they do. i gravitate towards editors that dont have it, and i will turn it off if i have to.

 

 

figbuzz: a programming language for writing fizzbuzz (requires python 2)

figbuzz is a program written in python– it translates a language called “figbuzz” into python. if this sounds a lot like fig, theres a good reason. figbuzz is a stripped-down fig compiler.

at 955 lines, figbuzz contains all the block functions of fig, plus the commands needed to write fizzbuzz, plus a command called “ismultipleof”. this demo (included in the download) will look familiar to those who know my fizzbuzz program written in fig:

#### license: creative commons cc0 1.0 (public domain)
#### http://creativecommons.org/publicdomain/zero/1.0/
for fb 1 100 1
    while
        ifmultipleof fb 5
            ifmultipleof fb 3
                now "fizzbuzz" print
                break
                fig
            fig
        ifmultipleof fb 5
            now "buzz" print
            break
            fig
        ifmultipleof fb 3
            now "fizz" print
            break
            fig
        now fb print
        break
        wend
    next

 

save the above program as fb.figb (or whatever-you-like.figb) and figbuzz will translate it into whatever-you-like.figb.py

figbuzz is not only an over-the-top fizzbuzz demo, its also a slightly more manageable version of fig to experiment with. everything is there, minus more than 50 of the usual commands.

figbuzz does not do graphics, figbuzz does not do colour. figbuzz does not require libraries, figbuzz only needs python 2.

(fig only needs python 2 in gnu/linux and mac os/x, but in windows it requires colorama.)

here is the source for figbuzz:

#!/usr/bin/env python
# coding: utf-8 
#### license: creative commons cc0 1.0 (public domain) 
#### http://creativecommons.org/publicdomain/zero/1.0/ 
proginf = "figbuzz 0.1, apr 2017 mn"
# a version of fig just for writing fizzbuzz
import sys
import os
from sys import stdin, stdout
from os import popen

buf = []

cmdhelp = [("timer", "input (shared-line) change main variable to number of seconds past midnight")

,("print", "output (shared-line) output main variable to the screen (aka stdout)")
,("prints", "output (shared-line) put main var to screen; like print but (s)tays on line.")
,("while", "loop --\\own\\line mark the start of a loop (will keep going without break)")
,("break", "loop --\\own\\line put in the middle of a loop to exit (stop looping)")
,("for var strt stop step", "loop --\\own\\line start a for loop, changing var from strt to stop, by step")
,("forin var array", "loop --\\own\\line loop through each item in array; for each, set var to item")
,("iftrue ckvar", "conditional --\\own\\line run lines between iftrue and fig if ckvar is \"non-zero\"")
,("ifequal var1 var2", "conditional --\\own\\line run lines between ifequal and fig if var1 equals var2")
,("ifmore var1 var2", "conditional --\\own\\line run lines between ifmore and fig if var1 is > var2")
,("ifless var1 var2", "conditional --\\own\\line run lines between ifless and fig if var1 is < var2")
,("ifmultipleof var1 var2", "conditional --\\own\\line run lines between ifless and fig if var1 is divisible evenly by var2")
,("try", "conditional --\\own\\line put code that might not work between try and except")
,("except", "conditional --\\own\\line if code between try/except fails, run the code after except")
,("resume", "conditional --\\own\\line mark the end of try / except / resume command block")
,("else", "conditional --\\own\\line after if- line, before fig. run lines if condition isnt true")
,("function name p1 p2 ...¦", "function --\\own\\line define function named name with optional params p1,p2, etc")
,("fig/next/nextin/wend", "fig (interchangeable) function --\\own\\line finalise a block (started by if/while/function/for/forin")
,("pass", "function --\\own\\line blocks (for/next, etc) require something inside lines; pass works / does nothing")
,("str", "function (shared-line) convert main variable from number to string")
,("not", "function (shared-line) change main variable to zero if non-zero; or -1 if zero")
,("#", "comment (can\\share) place at beginning (or end) of line, prior to a comment")
,("():;|=,. ( ) : ; | = , .", "optional (shared-line) use in a shared line (and some others) for aesthetics/notation")
,("system", "function (shared-line) put on (usually at the end of) a line to stop the program")
,("end", "function (shared-line) interchangeable with system which ends the program")
,("return var", "function (shared-line) (optional) exit current function, returning value var")
,("swap var1 var2", "function (shared-line) change contents of var1 to contents of var2 and vice-versa")
,("plus numstrarr", "math (shared-line) change main variable to itself plus num or string or arr")
,("minus numeric", "math (shared-line) change main variable to itself minus numeric")
,("divby numeric", "math (shared-line) change main variable to itself divided by numeric")
,("times numeric", "math (shared-line) change main variable to itself times numeric")
,("sgn", "math (shared-line) change main variable to 0 if 0, to -1 if < 0, or 1 if > 0.")
,("int", "math (shared-line) change main variable from decimal (aka \"float\") to integer")
,("mod denominator", "math (shared-line) change main variable to: main var modulus denominator")]

def chelp(f):
    ck = 0 ; print "" 
    for p in cmdhelp:
        rcmd = p[0]
        if f in rcmd.split()[0]:
            ck = 1
            rd = p[1].split()
            rcat = rd[0] ; rd.remove(rd[0])
            rt = rd[0] ; rd.remove(rd[0])

            cde = rcmd.split(" ")
            print "" 
            stdout.write("    " + colour(14,0)+ cde[0])
            cda = cde.remove(cde[0])
            for c in cde:
                stdout.write(" " + colour(0, 7)+ " " + c + " " + colour(7,0)+" ") ; stdout.flush()
            print "" 
            print "" 
            print colour(3,0) + "        category:", rcat, rt.replace("\\", " ") 
            print "" 
            print "        " + colour(7,0) + " ".join(rd) 
            print "" 
        colour(7,0);
    return ck

def outfilewrite(outb, p):
    outb += [p]
    #global vrck 
    #vrck += p.strip()
    #if inle: print colour(5, 0) + p.rstrip() ; p=raw_input() ; quit()

def colour(f, b):
    stdout.write("")
    return ""

def bcolour(b):
    stdout.write("")
    return ""

def sgn(p):
    p = float(p)
    if p > 0: return 1
    if p < 0: return -1
    return 0

def left(p, s):
    return p[:s]

def right(p, s):
    return p[-s:]

def leftfour(p):
    try: 
        if left(p, 4) == chr(32) * 4: p = right(p, len(p) - 4)
    except:
        pass
    return p

def atleast(s, p):
    if p < s: return s
    else: return p

def figfsp(p):
    pp = "" ; flg = 0 
    fsp = figfsplit(p)    
    for fp in enumerate(fsp):
        if flg == 0 and fp[1] in cmds.keys():
            pp += colour(8,0) + "_" + colour(7,0) + " " ; flg = cmds[fp[1]]
            if flg < 0: flg = flg * -1
            else: flg = flg + 1
        pp += fp[1] + " "
        if flg > 0:
            flg -= 1 
            if flg == 0 and fp[0] + 1 < len(fsp):
                pp += colour(8,0) + "_" + colour(7,0) + " "
    return pp.rstrip().replace(colour(8,0) + "_" + colour(7,0) + " " + colour(8,0) + 
    "_" + colour(7,0), colour(8,0) + "__" + colour(7,0)).replace(colour(8,0) + "_" + 
    colour(7,0),colour(8,0) + "__" + colour(7,0))

def figfsplit(p):
    # return p.split() # that was fine when strings weren't tokens
    # we have to make this 3 tokens: variable "hello, world!" #comment not string

    px = [] 
    pxc = -1 # could use len(px) -1 instead?

    inquotes = 0
    remarked = 0
    inspc = "" ; vnspc = ""

    #print "->", p

    for l in p:
        if inquotes == 0 and remarked == 0 and l == "#":
            remarked = 1
            pxc += 1 ; px += [""]
        if remarked == 1:
            px[pxc] += l

        if remarked == 0:
            if l == "\"":
                if inquotes == 0:
                    inquotes = 1 ; pxc += 1 ; px += [""]
                else: inquotes = 0 #; px[pxc] += l
        if inquotes == 1: px[pxc] += l

        if remarked == 0 and inquotes == 0:
            if vnspc not in "1234567890-" + chr(32) and l[0] == ".": l = " "
            vnspc = l
            if l[0] in "():;|=,": l = " "
            if inspc != " " and l == " ": pxc += 1 ; px += [""]
            if l != " ":
                if pxc == -1: pxc += 1 ; px += [""]
                px[pxc] += l.lower() 
            inspc = l
    #print "->", px[:]
    while ('') in px: px.remove('')
    while (':') in px: px.remove(':')
    for p in range(len(px)):
        if px[p][0] != "#":
            if right(px[p], 1) == ":":
                lenpx = len(px[p]) - 1
                if lenpx > 0:
                    px[p] = left(px[p], lenpx)
    return px[:]

def nob(p, s):
    r = ""
    if s == len(p) - 1:
        if len(p):
            if p[s].rstrip() != ".": r = p[s].rstrip()
        if len(r):
            if r[-1:] == ".": r = left(r, len(r) - 1)
    pfig = ""
    try: pfig = left(p[s], 3)
    except: pfig = ""
    if pfig.lower() == "fig" and p[s].lower() != "fig": return "figg"
    try: 
        if r != "": return r
        else: return p[s]
    except: return ""

def snobl(p):
    if "\"" in p: return p
    else: return p.lower()

def snob(p, s):
    r = ""
    if s == len(p) - 1:
        if len(p):
            if p[s].rstrip() != ".": r = p[s].rstrip()
        if len(r):
            if r[-1:] == ".": r = left(r, len(r) - 1)
    pqt = ""
    try: pqt = left(p[s], 3)
    except: pqt = ""
    if pqt.lower() == "fig" and p[s].lower() != "fig": return "figg"
    try: 
        if r != "": return snobl(r)
        else: return snobl(p[s])
    except: return ""

def lnob(p, s):
    r = ""
    if s == len(p) - 1:
        if len(p):
            if p[s].rstrip() != ".": r = p[s].rstrip()
        if len(r):
            if r[-1:] == ".": r = left(r, len(r) - 1)
    pfig = ""
    try: pfig = left(p[s], 3)
    except: pfig = ""
    if pfig.lower() == "fig" and p[s].lower() != "fig": return "figg"
    try: 
        if r != "": return r.lower()
        else: return p[s].lower()
    except: return ""

def getmore(p, s):
    try:
        for t in range(1, s + 1):
            if len(p) == 1: p = []
            p = right(p, len(p) - 1)
        while "" in p: p.remove("")
        for prx in range(len(p)):
            if p[prx][0] == "#":
                p.remove(p[prx])
        return p
    except: return []

def getlmore(p, s):
    try:
        for t in range(1, s + 1):
            if len(p) == 1: p = []
            p = right(p, len(p) - 1)
        while "" in p: p.remove("")
        return p
    except: return []

def lc():
    global linecount
    global flen
    es = " \x1b[0;37;40m"
    return "\x1b[0;37;44m" + right(chr(32) * flen + str(linecount), flen) + es

def wr(p):
    global buf
    buf += [p + "\n"]

colour(11, None) ; print proginf; colour(7, None) ; print

addtoout = [0]
addto = [0]

addtoout[0] = """import sys, os
from sys import stdin, stdout
from os import chdir as figoch
from os import popen as figpo
from os import system as figsh
from os import name as figosname
figsysteme = 0
figfilehandles = {}
figfilecounters = {}
"""

addtoout += [0] ; addto += [0]

addtoout[1] = """from sys import stdout
def fignonz(p, n=None):
    if n==None:
        if p == 0: return 1
    else:
        if p == 0: return n
    return p

def fignot(p):
    if p: return 0
    return -1

figbac = None
figprsbac = None
sub = None
def fignone(p, figbac):
    if p == None: return figbac
    return p
    return -1

\n"""
addtoout += [0] ; addto += [0]

addtoout[2] = ""
addtoout += [0] ; addto += [0]

addtoout[3] = ""

addtoout += [0] ; addto += [0]

# -2: print(variable, etc)
# -1: print(variable), 0: variable = int(variable), 1: variable=left(variable, etc)

cmds = {"str":0,
"prints":-1,"system":-1, "end":-1, 
"print":-1, 
"plus":1, "times":1, "divby":1, "minus":1,  
"int":0, "swap":-3, "return":-2, "mod":1, "not":0, "sgn":0}

funcs = {"function" : -1, "iftrue" : -2, "ifmultipleof" : -3, "ifequal" : -3, "ifless" : -3, 
"ifmore" : -3, "try":0, "except":0, "resume":0, "else":0}

ufunc = {}

#addfuncs = addtoout[0] + addtoout[1] + addtoout[3] + """
addfuncs = """

def figsgn(p):
    p = float(p)
    if p > 0: return 1
    if p < 0: return -1
    return 0

def figstr(p): return str(p)

def figprint(p): print p


def figprints(p): stdout.write(str(p)) ; sys.stdout.flush()

def figint(p): return int(p)

def figplus(p, s): 
    if type(p) in (float, int):
        if type(s) in (float, int):
            p = p + s
        else:
            p = p + s # float(s) if you want it easier
        if p == float(int(p)): p = int(p)
    else:
        if type(p) == str: p = p + s # str(s) if you want it easier
        if type(p) == list: 
            if type(s) == tuple:
                p = p + list(s)
            elif type(s) == list:
                p = p + s[:]
            else:
                p = p + [s]
        if type(p) == tuple: 
            if type(s) == tuple:
                p = tuple(list(p) + list(s))
            elif type(s) == list:
                p = tuple(list(p) + s[:])
            else:
                p = tuple(list(p) + [s])
    return p

def figtimes(p, s):
    if type(p) in (float, int):
        p = p * s # float(s) if you want it easier
        if p == float(int(p)): p = int(p)
    else:
        if type(p) == list:
            p = p[:] * s # figval(s)
        else:
            p = p * s # figval(s) if you want it easer
    return p
def figdivby(p, s):
    p = float(p) / s
    if p == float(int(p)): p = int(p)
    return p
def figminus(p, s): return p - s

def figmod(p, s): 
    return p % s

def figfunction(p, s): return p
def figend(x): quit()

def figsystem(x): quit()
\n"""

demo = """
for fb 1 100 1
    while
        ifmultipleof fb 5
            ifmultipleof fb 3
                now "fizzbuzz" print
                break
                fig
            fig
        ifmultipleof fb 5
            now "buzz" print
            break
            fig
        ifmultipleof fb 3
            now "fizz" print
            break
            fig
        now fb print
        break
        wend
    next
"""

p = ""
try: p = right(sys.argv, 1)[0]
except: pass
if not ".figb" in p.lower():
    if p.lower() == "help":
        stdout.write("\n    type (any) part of the command you want help on." +
        "\n\n    fig will show all matches.\n\n\n    ")
        helpf = chelp(raw_input())
        if not helpf: print(colour(14,0)+"\n    no commands match your search.") ; print("")
        colour(7,0)
    #try: inputfile = stdin.read().replace(chr(13), "").split("\n")
    #except: 
    #print "need an input file to do anything..."; print ; quit()
        quit()
    else:
        print "using built-in demo source, translating to demo.figb.py..." ; print
        p = "demo.figb"
        inputfile = demo.replace(chr(13), "").split("\n")
else:
    try:
        inputfile = open(p).read().replace(chr(13) + chr(10), 
        chr(10)).replace(chr(13), chr(10)).split(chr(10))
    except: print "couldn't open \"" + p + "\", exiting." ; print ; quit()
try: outfile = open(p + ".py", "w")
except: print "couldn't write to \"" + p + ".py" "\", exiting." ; print ; quit()
outname = p + ".py"

flen = len(str(len(inputfile)))

linecount = 0
indent = 0
inlinep = 0
inle = 0
errorin = 0
errorsrc = ""
error = ""
mode = 0
figraphics = -1 # -1 = uninitialised, 0 = textmode, 1 = initialised
vrs = []
vr = ""
outb = []
ingfx = 0
linesoutc = 0

for p in inputfile:
    linecount += 1 ; vrop = 0 ; vrcl = 0

    if linecount == 1: 
        outfile.write("#!/usr/bin/env python" + "\n# encoding: utf-8\n")
        if "," in proginf: 
            outfile.write("# figbuzz translator version: " + proginf.split(",")[0] + "\n")
    if inlinep:
        if p.lower().strip() == "fig":
            inlinep = 0
            print lc() + p
            indent = atleast(0, indent - 4)
        else:
            print lc() + colour(2, None) + p + colour(7, None)
            #% write copied lines of inline python
            outfilewrite(outb, chr(32) * atleast(0, indent - 4) + 
            leftfour(p) + "\n")

    elif mode == "output the following:":
        if p.lower().strip() == "display":
            mode = 0
            print lc() + p
        else:
            wr(chr(32) * atleast(0, indent) + "print \"" + p.replace(chr(34), 
            "\" + chr(34) + \"").replace(chr(92), "\" + chr(92) + \"") + "\"")
            print lc() + p.replace(chr(34), "\" + chr(34) + \"").replace(chr(92), 
            "\" + chr(92) + \"") 

    elif mode == 0:
        x = figfsplit(p.lstrip())
        lp = p.lower()
        if not len(p):
            print lc() + ""
            #% write copied blank lines from inline python
            outfilewrite(outb, "\n")

        if len(p.lstrip()):

            e = 0

            if p.lstrip()[0] == "#":
                if linecount == 1:
                    es = 0
                    try: 
                         if p.lstrip()[1] == "!": es = 1
                    except: es = 0
                    if not es:
                        wr(p)
                        print lc(), figfsp(p)
                    else: print lc() + "[this first comment isn't copied over]"
                    es = 0 
                else:
                    #% write comments
                    #print colour(14, 0) + p + colour(7,0) ; znul = raw_input()  #$ 
                    outfilewrite(outb, chr(32) * atleast(0, indent) + p + "\n")
                    print lc(), figfsp(p)

            elif lnob(x, 0) == "figg":
                 e = 2

            elif lp.rstrip() == "python":
                if 1 == 0:    
                    indent += 4
                    inlinep = 1
                    print lc() + p

            else:
                if not lnob(x, 0) == "figg":
                    if lnob(x, 0) != "fig" and not lnob(x, 
                    0) in cmds.keys() and not lnob(x, 
                    0) in funcs.keys() + ["forin", "for", "function", "nextin",
                    "next", "while", "wend"] + ["break", "pass"]: 
                        if not lnob(x, 0) in vrs: vrs += [lnob(x, 0)[:]] # main vars, also func params, etc
                        #% write variable
                        #var: print colour(14, 0) + "variable:" + lnob(x, 0) + colour(7,0) ; znul = raw_input()  #$
                        outfilewrite(outb, "\n")
                        outfilewrite(outb, chr(32) * atleast(0, indent) + 
                        "figlist = 0\n") 

                        outfilewrite(outb, chr(32) * atleast(0, indent) + 
                        "try: figlist = int(type(" + lnob(x, 0) + ") == list)\n")

                        outfilewrite(outb, chr(32) * atleast(0, indent) + 
                        "except NameError: pass\n")
                        outfilewrite(outb, chr(32) * atleast(0, indent) + 
                        "if not figlist: " + lnob(x, 0) + " = 0 \n")

                    if lnob(x, 0) == "fig":
                        #print lc () + p
                        #% write? its whitespace
                        #$
                        indent = atleast(0, indent - 4) 
                    if lnob(x, 0) == "wend":
                        #print lc () + p
                        #% write? its whitespace
                        #$
                        indent = atleast(0, indent - 4) 
                    if lnob(x, 0) == "next":
                        #print lc () + p
                        #% write? its whitespace
                        #$
                        indent = atleast(0, indent - 4) 
                    if lnob(x, 0) == "nextin":
                        #print lc () + p
                        #% write? its whitespace
                        #$
                        indent = atleast(0, indent - 4) 
                    if lnob(x, 0) == "try":
                        #print lc () + p
                        #% write try line
                        #$
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "try:\n")
                        indent = atleast(0, indent + 4) 
                    if lnob(x, 0) == "else":
                        #print lc () + p
                        #% write else line
                        #$
                        outfilewrite(outb, chr(32) * atleast(0, indent - 4) + 
                        "else:\n")
                    if lnob(x, 0) == "except":
                        #print lc () + p
                        indent = atleast(0, indent - 4) 
                        #% write except line
                        #$
                        outfilewrite(outb, chr(32) * atleast(0, indent) + 
                        "except:\n")
                        indent = atleast(0, indent + 4) 
                    if lnob(x, 0) == "resume":
                        #print lc () + p
                        #% write? its whitespace
                        #$
                        indent = atleast(0, indent - 4) 
                    if lnob(x, 0) == "while":
                        #print lc () + p
                        #% write simple loop
                        #$
                        outfilewrite(outb, chr(32) * atleast(0, indent) + 
                        "while 1:\n")
                        indent += 4 
                    if lnob(x, 0) == "function" and len(getmore(x, 1)) > 0:
                        #print lc () + p
                        mkf = []
                        funcname = getlmore(x, 1)[0]
                        prm = 1
                        while 1:
                            try:
                                aprm = getlmore(x, 1)[prm]
                                if len(aprm): 
                                    if aprm[0] != "#":
                                        mkf += [aprm]
                                        if aprm not in vrs: vrs += [aprm[:]]
                                prm += 1
                            except: break
                        ufunc[funcname] = mkf[:] #; print ufunc # #
                        #print ufunc
                        #print len(ufunc[funcname])
                        #% write func def
                        #$ print colour(14,0)+ "def " +  funcname + "(" + ", ".join(mkf) + "):" + colour(7,0)
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "def " +
                        funcname + "(" + ", ".join(mkf) + "):\n")
                        indent += 4

                    if lnob(x, 0) == "for" and len(getmore(x, 1)) == 4:
                        #print lc () + p
                        gmro = getlmore(x, 1)[0]
                        gmrt = getlmore(x, 1)[1]
                        gmrh = getlmore(x, 1)[2]
                        gmrf = getlmore(x, 1)[3]
                        if gmro not in vrs: vrs += [gmro[:]]
                        if "." not in gmrf and (gmrf.strip()) not in ("0", 
                        "0.0", "-0") and "." not in gmrt and "." not in gmrh: 
                            #% write standard for loop
                            #$
                            outfilewrite(outb, chr(32) * atleast(0, indent) 
                            + "for "
                            + gmro + " in range(int(float(" + gmrt + 
                            ")), int(float(" + gmrh + ")) + figsgn(" + gmrf + 
                            "), fignonz(int(float(" + gmrf + ")))):\n")
                        else:
                            #% write for loop that allows floating step
                            #$
                            outfilewrite(outb, chr(32) * atleast(0, indent) + gmro 
                            + " = float(" + gmrt + ") - float(" + gmrf + ")\n" + 
                            chr(32) * atleast(0, indent) + "while 1:\n" + chr(32) *
                            atleast(0, indent + 4) + gmro + " += float(" + gmrf +
                            ")\n" + chr(32) * atleast(0, indent + 4) + "if " + 
                            gmrf +
                            " > 0 and " + gmro + " > float(" + gmrh + "): break\n" 
                            + chr(32) * atleast(0, indent + 4) + "elif " + gmrf + 
                            " <= 0 and " + gmro + 
                            " < float(" + gmrh + "): break\n")
                        indent += 4

                    if lnob(x, 0) == "forin" and len(getmore(x, 1)) == 2:
                        #print lc () + p
                        gmro = getlmore(x, 1)[0]
                        gmrt = getlmore(x, 1)[1]
                        if gmro not in vrs: vrs += [gmro[:]]
                        #% write forin command with params
                        #$
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "for " +
                        gmro + " in " + gmrt + ":\n")
                        indent += 4

                    if lnob(x, 0) == "break":
                        #print lc () + p
                        #% write break command
                        #$ print
                        outfilewrite(outb, chr(32) * 
                        atleast(0, indent) + "break\n") 

                    if lnob(x, 0) == "pass":
                        #print lc () + p
                        #% write pass command
                        #$ print
                        outfilewrite(outb, chr(32) *
                        atleast(0, indent) + "pass\n") 

                    if lnob(x, 0) == "iftrue":
                        #print lc () + p
                        #% write iftrue
                        #$ print colour(14,0) + "if " +    snob(x, 1) + " > " + snob(x, 2) + ":\n"+ " ; " +colour(7,0)
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "if " + 
                        snob(x, 1) + ":\n") ; indent += 4

                    if lnob(x, 0) == "ifequal" and len(getmore(x, 1)) == 2:
                        #print lc () + p
                        #% write ifequal
                        #$ print colour(14,0) + "if " +    snob(x, 1) + " > " + snob(x, 2) + ":\n"+ " ; " +colour(7,0)
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "if " + 
                        snob(x, 1) + " == " + snob(x, 2) + ":\n") ; indent += 4

                    if lnob(x, 0) == "ifless" and len(getmore(x, 1)) == 2:
                        #print lc () + p
                        #% write ifless
                        #$ print colour(14,0) + "if " +    snob(x, 1) + " > " + snob(x, 2) + ":\n"+ " ; " +colour(7,0)
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "if " +
                        snob(x, 1) + " < " + snob(x, 2) + ":\n") ; indent += 4

                    if lnob(x, 0) == "ifmultipleof" and len(getmore(x, 1)) == 2:
                        #print lc () + p
                        #% write ifless
                        #$ print (colour(14,0) + "if " +    float(snob(x, 1)) + " / " + 
                        #snob(x, 2) + " == int(" +  snob(x, 1) + " / " + snob(x, 2) + "):\n"+ 
                        #" ; " +colour(7,0))
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "if float(" +
                        snob(x, 1) + ") / " + snob(x, 2) + " == int(" + snob(x, 1) + " / " + 
                        snob(x, 2) + "):\n") ; indent += 4

                    if lnob(x, 0) == "ifmore" and len(getmore(x, 1)) == 2:
                        #print lc () + p
                        #% write ifmore
                        #$ print colour(14,0) + "if " +    snob(x, 1) + " > " + snob(x, 2) + ":\n"+ " ; " +colour(7,0)
                        outfilewrite(outb, chr(32) * atleast(0, indent) + "if " + 
                        snob(x, 1) + " > " + snob(x, 2) + ":\n") ; indent += 4

                    if lnob(x, 0) in cmds.keys(): # + ufunc.keys():
                        e = 4 ; shln = lnob(x, 0) 

                    if lnob(x, 0) != "fig" and lnob(x, 
                    0) not in funcs.keys() + ["forin", "for", "function", 
                    "nextin", "next", "while", "wend"] + ["break", "pass"]:

                        #print lc () + p
                        vr = lnob(x, 0)
                        #print vr, type(vr)
                        #print getlmore(x, 1)
                        prsc = 0
                        cstrctr = 0
                        csbuf = []
                        vrcs = ""
                        for prs in getlmore(x, 1):                            
                            #$ print prs 
                            if "fig" in prs:
                                if prs[:3] == "fig": e = 2 ; break ; break
                            if prs in funcs.keys():
                                e = 3 ; shln = prs
                            prsc += 1
                            if cstrctr > 0:
                                vrcs += prs
                                cstrctr -= 1
                                if cstrctr == 0:

                                    if lnob(x, prsc - 1) == "return":
                                        #% write return command
                                        #$ print colour(14,0) +vrcs + " ; " +colour(7,0)
                                        outfilewrite(outb, chr(32) * atleast(0, 
                                        indent) + vrcs)

                                    elif lnob(x, prsc - 2) == "swap":
                                        vrcs = lnob(x, prsc - 1) + ", " + lnob(x,
                                        prsc - 0) + " = " + lnob(x, 
                                        prsc - 0) + ", " + lnob(x, prsc - 1)
                                        #% write swap of 2 vars in python syntax
                                        #$ print colour(14,0) +vrcs + " ; " +colour(7,0)
                                        outfilewrite(outb, chr(32) * atleast(0,
                                        indent) + vrcs + " ; ")
                                    else:

                                        if figprsbac in ufunc.keys():
                                            #% write parametered func call 
                                            #$ print colour(14,0)+  vrcs + ") ; " + lnob(x, 0) + " = fignone(" + lnob(x, 0) + ", figbac) ; " +colour(7,0)
                                            outfilewrite(outb, chr(32) * atleast(0,
                                            indent) + vrcs + ") ; " + lnob(x, 0) +
                                            " = fignone(" + lnob(x, 0) +
                                            ", figbac) ; ") ; vrcl += 1
                                        else:
                                            #% write builtin func call assignment
                                            #$ print colour(14,0)+  vr + " = " +  vrcs + ") ; "  +colour(7,0)
                                            outfilewrite(outb, chr(32) *
                                            atleast(0, indent) + vrcs + ") ; ") ; vrcl += 1
                                else:
                                    vrcs += ", " #; print "*"
                                    #if 
                                continue

                            if prs.lower() in funcs.keys() + ["forin", "for",
                            "function", "nextin", "next", "while", 
                            "wend"] + ["break", "pass"]:
                                e = 3
                            figprsbac = None

                            if cstrctr == 0:
                                if not prs.lower() in vrs:
                                    if prs.lower()[0] in "abcdefghijklmnopqrstuvwxyz":
                                        if not prs.lower() in ufunc.keys():
                                            if not prs.lower() in funcs.keys():
                                                if not prs.lower() in cmds.keys():
                                                    e = 5 ; shln = prs

                            if prs.lower() in vrs and cstrctr == 0: 
                                #and len(getmore(x, 1)) == 1:
                                #% write lefthand variable assignment
                                #$ print colour(14,0)+  vr + " = " + prs.lower()  +colour(7,0)
                                outfilewrite(outb, chr(32) * atleast(0, indent) +
                                vr + " = " + prs.lower() + "\n")

                            if prs[0] == "\"":
                                #% write string assignment (any place in shared line)
                                outfilewrite(outb, chr(32) * atleast(0, indent) +
                                vr + " = " + prs + " ; ")

                            if prs[0] in ".1234567890-":
                                #% write numerics
                                outfilewrite(outb, chr(32) * atleast(0, indent) + 
                                vr + " = " + prs + " ; ")

                            if prs[0] == "#": 
                                #% write trailing comments #$ print colour(14, 0) + prs  + colour(7,0)
                                outfilewrite(outb, prs + "\n") ; break


                            if prs.lower() in ufunc.keys():
                                #% write pre-func-call var backup for sub-style behavior #$ print colour(14, 0) + "figbac = " + lnob(x,0) + " ; " + colour(7,0)
                                outfilewrite(outb, chr(32) * atleast(0, indent) +
                                "figbac = " + lnob(x,0) + " ; " ) # ##
                                figprsbac = prs.lower()	

                                cstrctr = len(ufunc[prs])
                                #print cstrctr
                                if cstrctr == 0:
                                    #% write zero-param func/?sub call
                                    #$ print colour(14, 0) + vr + " = " + prs.lower() + "() ; " + lnob(x, 0) + " = fignone(" + lnob(x, 0) + ", figbac) ; " + colour(7,0)
                                    outfilewrite(outb, chr(32) * 
                                    atleast(0, indent) + 
                                    vr + " = " + prs.lower() + "() ; " + lnob(x, 0) +
                                            " = fignone(" + lnob(x, 0) + ", figbac) ; ") # #
                                else:
                                    #print "y"
                                    vrop += 1
                                    vrcs = vr + " = " + prs.lower() + "(" 
                                    #$ print colour(4, 0) + vr + " = " + prs.lower() + "(" + colour(7,0) #$
                                    #multiparameter  


                            if prs.lower() in cmds.keys():
                                if prs.lower() in ["display", "pset", "line"]: 
                                    ingfx = 1
                                ##print prs	
                                cstrctr = cmds[prs]
                                ##print cstrctr
                                if cstrctr == -1:
                                    #% write zero-param subs
                                    #print colour(14, 0) + "fig" +  prs.lower() + "(" + vr 
                                    #+ ") ; " + colour(7,0) ; #znul = raw_input()  #$
                                    outfilewrite(outb, chr(32) * 
                                    atleast(0, indent) + "fig" + 
                                    prs.lower() + "(" + vr + ") ; " ) ; vrcl += 1

                                if cstrctr == 0:
                                    #% write zero-param functions 
                                    #print colour(14, 0) + vr + " = fig" + prs.lower() 
                                    #+ "(" + vr + ") ; "+ colour(7,0) ; #znul = raw_input()  #$
                                    outfilewrite(outb, chr(32) * atleast(0,
                                    indent) + vr +
                                    " = fig" + prs.lower() + "(" + vr + ") ; " ) ; vrcl += 1

                                if cstrctr < -1:
                                    if prs == "return":

                                        cstrctr = abs(cstrctr) - 1
                                        vrcs = "return " #parameter
                                    else:
                                        cstrctr = abs(cstrctr) - 1
                                        if prs == "swap": vrcs = "swap "
                                        else:
                                            vrop += 1
                                            vrcs = "fig" + prs.lower() + "(" + vr 
                                            vrcs += ", " #multiparameter  
                                else:
                                    vrop += 1
                                    vrcs = vr + " = fig" + prs.lower() + "(" + vr 
                                    vrcs += ", " #multiparameter  

                        if vrop == vrcl and e == 0: 
                            print lc(), figfsp(p)

                        #% finish each line with lf
                        outfilewrite(outb, "\n")
                    else:
                        print lc() + p
                else:
                    e = 2

            if e == 1: 
                e = 0 
                if not len(error):
                    error = "error: problem in command structure or details."
                    errorin = linecount
                    errorsrc = p
                print lc() + colour(14, 0) + str(p) + colour(7, 0)
                break

            if e == 2:
                e = 0
                if not len(error):
                    error = "error: cannot create variable or function beginning"
                    error += " with \"fig\""
                    errorin = linecount
                    errorsrc = p
                print lc() + colour(14, 0) + p + colour(7, 0)
                break

            if e == 3:
                e = 0
                if not len(error):
                    error = "error: single-line command \"" + shln + "\" not on own line"
                    errorin = linecount
                    errorsrc = p
                print lc() + colour(14, 0) + p + colour(7, 0)
                break

            if e == 4:
                e = 0
                if not len(error):
                    error = "error: shared-line function \""
                    error += shln + "\" cannot be used to start a line"
                    errorin = linecount
                    errorsrc = p
                print lc() + colour(14, 0) + p + colour(7, 0)
                break

            if e == 5:
                e = 0
                if not len(error):
                    error = "error: variable or function not created, but referenced... \""
                    error += shln + "\" needs to be set before first use"
                    errorin = linecount
                    errorsrc = p
                print lc() + colour(14, 0) + p + colour(7, 0)
                break

    if vrcl != vrop: 
                e = 0 
                if not len(error):
                    error = "error: a command has the wrong number of parameters."
                    errorin = linecount
                    errorsrc = p
                print lc() + colour(14, 0) + str(p) + colour(7, 0)
                break

if ingfx == 0: addtoout[3] = ""
outfile.write(addtoout[0] + addtoout[1] + addtoout[3] + addfuncs)
for outsb in outb: outfile.write(outsb)
outfile.close()

print
if errorin:
    print error ; colour(14, None) ; print "error in line " + str(errorin) + ":"
    colour(7, None)
    print errorsrc
    #from os import system as stf ; p = stf("touch e")
else:
    try: os.system("chmod +x \"" + outname + "\"")
    except: pass
    colour (11, None) ; print "translation complete. ", ; colour(7, None)
    print "here's a python script you can run: ", 
    print colour(11, None) + outname + colour(7, None)
print