Skip to main content

Ralsina.Me — Roberto Alsina's website

Posts about programming (old posts, page 23)

Snow and rates

Mon­day was a very spe­cial day:

  • Hol­i­­day (In­de­pen­­dence day)

  • An­niver­sary (3 years as Rosar­i­o's boyfriend)

  • The first snow­­fall in Buenos Aires in 89 years.

Be­sides that, this week my broth­er is get­ting mar­ried so the whole fam­i­ly (in­clud­ing 2.5 mon­th-old JF) is leav­ing for my an­ces­tral lands to­mor­row.

And I start­ed a new small pro­jec­t, wh­cih should be fin­ished soon.

This is some­thing that seems use­ful to me in the con­text of mail server­s, but maybe it will al­so find its us­es else­where.

I call it rater, and it tells you if things are hap­pen­ing faster than a spe­cif­ic rate.

For ex­am­ple, I in­tend to use it to fig­ure out if a spe­cif­ic IP is con­nect­ing to a serv­er more than X times ev­ery Y sec­ond­s, or if a us­er is send­ing more than Z emails ev­ery T min­utes.

The on­ly thing I found for this is re­lay­d, which is old, un­main­tained and whose site has van­ished.

The con­fig file is some­thing like this (thanks to lib­con­fig):

limits : {
      user: (
                    ("rosario",90,20),
                    ("ralsina",90,10),
              ("*",2,10)
              );
      ip:   (
                    ("10.0.0.*",90 , 20),
                    ("10.0.1.*",90 , 20),
                    ("*",2 , 10)
              );

};

You can de­fine as many class­es of lim­its as you want (that would be ip and us­er in this ex­am­ple) and as many lim­it keys as you wan­t, that will be matched us­ing some­thing like fn­match.

I am us­ing an in­-mem­o­ry SQLite DB for the ac­count­ing, and an in­ter­est­ing li­brary called libut for the sock­et­s, log­ging, and event loop.

This li­brary has a very in­ter­est­ing fea­ture: your app gets an ad­min­is­tra­tive in­ter­face for free!

[ralsina@monty rater]$ telnet localhost 4445
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
libut control port interpreter
Type 'help' for command list.

help
command           description
----------------- -------------------------------------
* mem             - memory pool usage summary
* var             - Display or set config variables
* log             - Change log file or verbosity
  fds             - list selected file descriptors
  tmr             - show pending timers
  uptime          - show uptime
* prf             - Performance/profiling stats
* cops            - List coprocesses
  help            - view command help
  exit            - close connection

Commands preceded by * have detailed help. Use help <command>.

Ok
var
 name                 description                    value
--------------------- ------------------------------ --------------------
*ut_log_level         log level                      Debugk
*ut_log_file          log file                       /dev/stdout
*ut_jobname           job name                       job1
*ut_control_port      control port IP/port           127.0.0.1:4445
*ut_basedir           shl base directory             /mnt/centos/home/ralsina/Desktop/proyectos/rater

Variables prefixed with '*' can be changed.

Ok
var ut_log_level Debug

Ok
var
 name                 description                    value
--------------------- ------------------------------ --------------------
*ut_log_level         log level                      Debug
*ut_log_file          log file                       /dev/stdout
*ut_jobname           job name                       job1
*ut_control_port      control port IP/port           127.0.0.1:4445
*ut_basedir           shl base directory             /mnt/centos/home/ralsina/Desktop/proyectos/rater

Variables prefixed with '*' can be changed.

Ok

Pret­ty neat.

Be­yond this, there will be a small clien­t-­side li­brary that hides all the net­work stuff be­hind a cou­ple of block­ing calls (or you can do your own be­cause the pro­to­col is sil­ly sim­ple).

Quote of the day (ok, of May 21st, 2007, but I only saw it today)

Said Giles Bowkett

The Perl com­mu­ni­ty's start­ing to look more and more like the Lisp com­mu­ni­ty ev­ery day. The com­bi­na­tion of in­cred­i­ble pow­er, reclu­sive wiz­ard­s, and an­ti­so­cial Slash­dot­ters gives it the vibe of a lava-­filled waste­land dot­ted with tow­ers where strange men with white beards ob­sess over un­speak­able knowl­edge. I spoke to some­one once who com­pared pro­gram­ming in Lisp to study­ing Kab­bal­ah, in that it does strange things to your head. Parts of Perl are like that. Stil­l, source fil­ter­ing's kind of cool. Un­nec­es­sary, but cool.

So, now we know. Saru­man used too much Per­l.

The Linux software ecosystem is boring and a little lame (a rant).

Quick, an­swer this:

What was the last time a ba­sic piece of the Lin­ux sys­tem was re­designed and re­placed by ev­ery­one?

And the new piece was not a drop-in re­place­ment or evo­lu­tion­ary de­vel­op­ment for the old garbage?

Please post the an­swers on com­ments, be­cause the best I can come up with is one of the fol­low­ing:

  • Post­­fix re­­plac­ing Send­­mail

  • Ev­ery­thing else re­­plac­ing Wu-ft­pd

  • GRUB re­­plac­ing LILO ? (not that GRUB is all that great, but at least you have a de­­cent chance of fix­ing it when it break­s)

  • OpenSSH re­­plac­ing tel­net and rlogin

There are still dis­tros ship­ping Wu-imap and its off­spring!

There are still dis­tros ship­ping the old sys­log!

Let's con­sid­er a ba­sic, tty Lin­ux first.

  1. GRUB (ok)

  2. Lin­ux ker­nel (ok I guess)

  3. An­­cient SysV init (un­­less you use par­­dus/­­gob­­o/­­some oth­­er rad­i­­cal dis­­tro)

  4. Ser­vices, which prob­a­bly in­­­clude

    1. Sys­log-NG (which is marginal­­­ly less bro­ken than old sys­log)

    2. Send­­­mail (even if on­­­ly for loop­back ad­­­dress­es, it's still lame)

    3. OpenSSH (ok, al­though I think the client sucks be­­­cause I can't fig­ure out how to store pass­­­words and pass­fras­es in KWal­let)

  5. A get­­ty

At least here there is not much room for in­no­va­tion be­cause we are try­ing to start some­thing that is a lot like a 30-year-old Unix box.

So, let's go server-ish. What would you nor­mal­ly use?

  • BIND

    An­­cient soft­­ware with a ter­ri­ble se­cu­ri­­ty his­­to­ry. Yes I know it's rewrit­ten late­­ly. They did that be­­fore, too, you know.

  • Apache

    For all the good things Apache has, it has some bad ones, too.

    • It's overkill for most server­s.

    • As the A in LAMP it has lead peo­­­ple to be­lieve PH­P4 is the right lan­guage to de­vel­op ap­­­pli­­­ca­­­tions in, and MySQL a good place to store their da­­­ta.

    • If it fails to do what you wan­t, you may get an er­ror. Or not.

    • The con­­­fig­u­ra­­­tion is in some sort of pseu­­­do-XML

    Let's get re­al. For most mod­­ern web apps what you want is a de­­cen­t, high per­­for­­mance WS­­GI thingie for python ap­p­s, and what­ev­er you use for Rail­s. Apache may or may not be that or have that in­­sid­e, but who needs the rest of it? What for? PHP pages? mod­­_perl web ap­p­s?

    No, re­al­­ly, I'm ask­ing a ques­­tion here. What pieces of Apache do you use nowa­­days?

  • Sam­­ba

    • It does what it does.

    • Noone else does it.

    • Er­­­go, it's the best at what it does.

    • That does­n't mean that los­ing its TDB ev­ery once in a while while do­ing a "R­PC vam­pire" is not an­noy­ing.

    But ac­­tu­al­­ly, I am pret­­ty hap­py about Sam­­ba. I mean, what's the al­ter­­na­­tive, here? NF­reak­ingS?

  • CUPS

    Ok, not too many new print servers out there, but hey, it's bet­ter than LPRng!

And if I had writ­ten this rant three years ago, I would have used the ex­act same ex­am­ples.

Where's the vi­brant new serv­er ap­p?

Who's go­ing to write a cool, per­form­ing, easy to con­fig­ure HTTP+WS­GI serv­er in D?

Who's go­ing to im­ple­ment a fast, se­cure, sim­ple, ze­ro­con­f-en­abled, file serv­ing dae­mon?

Who's go­ing to re­place BIND?

Who's go­ing to cre­ate a Lin­ux serv­er dis­tro with on­ly de­cent soft­ware in it?

Me? No way, I have di­a­pers to change. And there used to be smarter and more driv­en peo­ple around to do this stuff. Are they all chang­ing di­a­pers now?

Come on, stop re­hears­ing with your band that plays "met­al with me­dieval in­flu­ences"! Stop grow­ing your stamp col­lec­tion! Stop

Come on, it's on­ly go­ing to con­sume at most a year or two of your life. It's not go­ing to harm you more than a bud­ding al­co­holis­m, or a po­et­ry hob­by, or at­tend­ing fur­ry con­ven­tion­s, young man (or wom­an)!

You don't need to be all that knowl­edge­able (look at the BIND4 sources) or bril­liant, all you need is to be in­dus­tri­ous.

Grow a spine and get crank­ing! Show us old hacks what you've got!

Old READMEs: Atlast... make everything programmable!

I have been ex­plor­ing em­bed­dable lan­guages for the last month or so. I have learned forth and some of its many many many vari­ants 1 and while ex­plor­ing one of the most ob­scure ones called At­last 2, I found a very in­ter­est­ing README which I will quote lib­er­al­ly in this post.

Vir­tu­al­ly ev­ery in­dus­try an­a­lyst agrees that open ar­chi­tec­ture is es­sen­tial to the suc­cess of ap­pli­ca­tion­s. And yet, even to­day, we write pro­gram af­ter pro­gram that is closed--that its users can­not pro­gram--that ad­mits of no ex­ten­sions with­out our adding to its source code. If we be­lieve in­tel­lec­tu­al­ly, from a sound un­der­stand­ing of the eco­nom­ic in­cen­tives in the mar­ket­place, that open sys­tems are bet­ter, and have seen this be­lief con­firmed re­peat­ed­ly in the mar­ket­place, then the on­ly ques­tion that re­mains is why? Why not make ev­ery pro­gram an open pro­gram?

And this is in­deed very im­por­tan­t. Any app worth de­vel­op­ing is prob­a­bly worth de­vel­op­ing in an ex­ten­si­ble man­ner. Af­ter al­l, you are prob­a­bly nev­er go­ing to fig­ure out what the us­er re­al­ly wants to do.

But why is not ev­ery pro­gram "open" in this man­ner?

Well, be­cause it's HARD! Writ­ing a closed pro­gram has tra­di­tion­al­ly been much less work at ev­ery stage of the de­vel­op­ment cy­cle: eas­i­er to de­sign, less code to write, sim­pler doc­u­men­ta­tion, and far few­er con­sid­er­a­tions in the test phase. In ad­di­tion, closed prod­ucts are be­lieved to be less de­mand­ing of sup­port, al­though I'll ar­gue lat­er that this as­sump­tion may be in­cor­rec­t.

This is true, al­though it was much more true in 1991 when At­last was re­leased to the pub­lic do­main. Nowa­days the gen­er­al­ized adop­tion of more dy­nam­ic lan­guages has made this much eas­i­er. Af­ter al­l, you can write a plug­in sys­tem for your python app in per­haps ten lines of code.

How­ev­er, there is a strong back­lash from the pains of MSOf­fice script­ing, which in­volved love­li­ness like func­tion names that changed ac­cord­ing to your lo­cale, and ba­sic as the lan­guage of choice.

On stat­ic lan­guages this is hard­er, but there are tech­no­log­i­cal so­lu­tion­s. For ex­am­ple, in KDE there is al­ready a lim­it­ed script­abil­i­ty cul­ture based on how easy it is to pro­vide ex­ter­nal DCOP in­ter­faces (I sup­pose I should say DBUS nowa­days). Al­so for KDE4 the Kross script­ing frame­work prom­ises lan­guage-neu­tral script­ing.

Most pro­grams start out as non­pro­grammable, closed ap­pli­ca­tion­s, then painful­ly claw their way to pro­gramma­bil­i­ty through the in­tro­duc­tion of a lim­it­ed script or macro fa­cil­i­ty, suc­ceed­ed by an in­creas­ing­ly com­pre­hen­sive in­ter­pre­tive macro lan­guage which grows like top­sy and with­out a co­her­ent de­sign as us­er de­mands up­on it grow. Fi­nal­ly, per­hap­s, the pro­gram is out­fit­ted with bind­ings to ex­ist­ing lan­guages such as C.

Noone pro­vides straight cus­tom C bind­ings for ap­pli­ca­tions now, right? But yes, I ex­pect script­ing is not the first thing that gets im­ple­ment­ed.

An al­ter­na­tive to this is adopt­ing a stan­dard lan­guage as the macro lan­guage for a prod­uc­t. This ap­proach has many at­trac­tion­s. First, choos­ing a stan­dard lan­guage al­lows users to avail them­selves of ex­ist­ing books and train­ing re­sources to learn its ba­sic­s. The de­vel­op­er of a ded­i­cat­ed macro lan­guage must cre­ate all this ma­te­ri­al from scratch. Sec­ond, an in­ter­pre­tive lan­guage, where all pro­grams are rep­re­sent­ed in ASCII code, is in­her­ent­ly por­ta­ble across com­put­ers and op­er­at­ing sys­tem­s. Once the in­ter­preter is got­ten to work on a new sys­tem, all the pro­grams it sup­ports are pret­ty much guar­an­teed to work. Third, most ex­ist­ing lan­guages have evolved to the point that most of the rough edges have been tak­en off their de­sign. Ex­tend­ing an ex­ist­ing lan­guage along the lines laid down by its de­sign­ers is much less like­ly to re­sult in an in­com­pre­hen­si­ble dis­as­ter than grow­ing an ad-hoc macro lan­guage fea­ture by neat-o fea­ture.

Un­for­tu­nate­ly, in­ter­preters are slow, slow, slow. A sim­ple cal­cu­la­tion of the num­ber of in­struc­tions of over­head per in­struc­tion that fur­thers the ex­e­cu­tion of the pro­gram quick­ly demon­strates that no in­ter­preter is suit­able for se­ri­ous com­pu­ta­tion. As long as the in­ter­preter is de­ployed in the role of a macro lan­guage, this may not be a sub­stan­tial con­sid­er­a­tion. How­ev­er, as soon as ap­pli­ca­tions try to do sub­stan­tial com­pu­ta­tion, the over­head of an in­ter­preter be­comes a crush­ing bur­den, verg­ing on in­tol­er­a­ble. The ob­vi­ous al­ter­na­tive is to pro­vide a com­piled lan­guage. But that, too, has its prob­lem­s.

In­ter­est­ing point here is that again, the speed of in­ter­preters is not so big a deal nowa­days. Af­ter al­l, Lu­a­JIT is pret­ty fast for most us­es.

Us­ing a com­pil­er as an ex­ten­sion lan­guage is not some­thing I have run in­to but I could do some pret­ty things us­ing, for ex­am­ple, TCC, Python and python-in­stant.

Now we get to AT­LAST it­self:

AT­LAST is a tool­kit that makes ap­pli­ca­tions pro­gram­mable. De­lib­er­ate­ly de­signed to be easy to in­te­grate both in­to ex­ist­ing pro­grams and new­ly-de­vel­oped ones, AT­LAST pro­vides any pro­gram that in­cor­po­rates it most of the ben­e­fits of pro­gramma­bil­i­ty with very lit­tle ex­plic­it ef­fort on the part of the de­vel­op­er. In­deed, once you be­gin to "think AT­LAST" as part of the de­sign cy­cle, you'll prob­a­bly find that the way you de­sign and build pro­grams changes sub­stan­tial­ly. I'm com­ing to think of AT­LAST as the "mon­ster that feeds on pro­gram­s," be­cause in­clud­ing it in a pro­gram tends to shrink the amount of spe­cial-pur­pose code that would oth­er­wise have to be writ­ten while re­sult­ing in fin­ished ap­pli­ca­tions that are open, ex­ten­si­ble, and more eas­i­ly adapt­ed to oth­er op­er­at­ing en­vi­ron­ments such as the event driv­en par­a­digm.

The idea of a por­ta­ble toolk­it, in­te­grat­ed in­to a wide va­ri­ety of prod­uct­s, all of which there­by share a com­mon pro­gram­ming lan­guage seems ob­vi­ous once you con­sid­er its ad­van­tages. It's sur­pris­ing that such pack­ages aren't com­mon­place in the in­dus­try. In fac­t, the on­ly true an­tecedent to AT­LAST I've en­coun­tered in my whole twist­ed path through this in­dus­try was the uni­ver­sal macro pack­age de­vel­oped in the mid 1970's by Kern Sib­bald and Ben Cranston at the Uni­ver­si­ty of Mary­land. That pack­age, im­ple­ment­ed on Uni­vac main­frames, pro­vid­ed a com­mon macro lan­guage shared by a wide va­ri­ety of Uni­ver­si­ty of Mary­land util­i­ties, in­clud­ing a text ed­i­tor, de­bug­ger, file dumper, and type­set­ting lan­guage. While AT­LAST is en­tire­ly dif­fer­ent in struc­ture and op­er­a­tion from the Mary­land pack­age, which was an in­ter­pre­tive string lan­guage, the con­cept of a cross-prod­uct macro lan­guage and ap­pre­ci­a­tion of the ben­e­fits to be had from such a pack­age are di­rect­ly trace­able to those root­s.

This con­cept was lat­er adopt­ed by Lu­a, Tcl, and you could use Python in this man­ner, al­though usu­al­ly it's done the oth­er way around. Which means that there is not so much shar­ing of ex­ten­sion lan­guages as there could be.

And on­to the con­clu­sion­s:

Ev­ery­thing should be pro­gram­mable. EV­ERY­THING! I have come to the con­clu­sion that to write al­most any pro­gram in a closed man­ner is a mis­take that in­vites the ex­pen­di­ture of un­count­ed hours "en­hanc­ing" it over its life cy­cle. Fur­ther tweak­s, "fea­tures," and "fix­es" of­ten re­sult in a prod­uct so mas­sive and in­com­pre­hen­si­ble that it be­comes un­learn­able, un­main­tain­able, and even­tu­al­ly un­us­able.

Amen.

Far bet­ter to in­vest the ef­fort up front to cre­ate a prod­uct flex­i­ble enough to be adapt­ed at will, by its user­s, to their im­me­di­ate need­s. If the prod­uct is pro­gram­mable in a portable, open for­m, us­er ex­ten­sions can be ex­changed, com­pared, re­viewed by the prod­uct de­vel­op­er, and even­tu­al­ly in­cor­po­rat­ed in­to the main­stream of the prod­uc­t.

This pre­fig­ures the cur­rent FLOSS ecosys­tem, which is pret­ty im­pres­sive for a prod­uct that was ma­ture in 1991, al­though of course there was al­ready a com­mu­ni­ty of EMACS hack­ing and sim­i­lar nich­es.

It is far, far bet­ter to have thou­sands of cre­ative users ex­pand­ing the scope of one's prod­uct in ways the orig­i­nal de­vel­op­ers did­n't an­tic­i­pate--in fac­t, work­ing for the ven­dor with­out pay, than it is to have thou­sands of frus­trat­ed users writ­ing up wish list re­quests that the ven­dor can com­ply with on­ly by hir­ing peo­ple and pay­ing them to try to ac­com­mo­date the per­ceived needs of the user­s.

True if a lit­tle too cyn­i­cal for my cur­rent taste ;-) Of course in FLOSS there is no such con­flict be­tween users and de­vel­op­ers be­cause the de­vel­op­ers can usu­al­ly just whine ex­­plain to the users the re­al­i­ties of free soft­­ware de­vel­op­­men­t. But hey, a low bar­ri­er to en­try is al­ways a nice thing to have.

Open ar­chi­tec­ture and pro­gramma­bil­i­ty not on­ly ben­e­fits the user, not on­ly makes a prod­uct bet­ter in the tech­ni­cal and mar­ket­ing sense, but con­fers a di­rect eco­nom­ic ad­van­tage up­on the ven­dor of such a pro­duc­t--one mir­rored in a com­men­su­rate dis­ad­van­tage to the ven­dor of a closed prod­uc­t.

The chief ar­gu­ment against pro­gramma­bil­i­ty has been the ex­tra in­vest­ment need­ed to cre­ate open prod­uct­s. AT­LAST pro­vides a way of build­ing open prod­ucts in the same, or less, time than it takes to con­struct closed ones. Just as no C pro­gram­mer in his right mind would sit down and write his own buffered file I/O pack­age when a per­fect­ly fine one was sit­ting in the li­brary, why re-in­vent a macro lan­guage or oth­er pa­ram­e­ter­i­sa­tion and pro­gram­ming fa­cil­i­ty when there's one just sit­ting there that's as fast as na­tive C code for all but the most ab­surd mis­ap­pli­ca­tion­s, takes less than 51K with ev­ery gew-­gaw and op­tion­al fea­ture at its com­mand en­abled all at on­ce, is por­ta­ble to any ma­chine that sup­ports C by sim­ply re­com­pil­ing a sin­gle file, and can be in­te­grat­ed in­to a typ­i­cal ap­pli­ca­tion at a ba­sic lev­el in less than 15 min­utes?

And then pro­ceeds to throw a Forth vari­ant at you ;-) Good con­cep­t, per­haps not the nicest lan­guage to use, al­though the choice is very un­der­stand­able.

Am I propos­ing that ev­ery ap­pli­ca­tion sud­den­ly look like FORTH? Of course not; no more than out­put from Post­Script print­ers looks like PostScrip­t, or ap­pli­ca­tions that run on 80386 pro­ces­sors re­sem­ble 80386 as­sem­bly lan­guage. AT­LAST is an in­ter­me­di­ate lan­guage, seen on­ly by those en­gaged in im­ple­ment­ing and ex­tend­ing the prod­uc­t. Even then, AT­LAST is a chameleon which, with prop­er­ly de­fined word­s, can look like al­most any­thing you like, even at the prim­i­tive lev­el of the in­ter­preter.

Again and again, I have been faced with de­sign sit­u­a­tions where I knew that I re­al­ly need­ed pro­gramma­bil­i­ty, but did­n't have the time, the mem­o­ry, or the for­ti­tude to face the prob­lem square­ly and solve it the right way. In­stead, I end­ed up cre­at­ing a kludge that con­tin­ued to bur­den me through time. This is just a high­er lev­el man­i­fes­ta­tion of the night­mares per­pe­trat­ed by old-­time pro­gram­mers who did­n't have ac­cess to a prop­er dy­nam­ic mem­o­ry al­lo­ca­tor or linked list pack­age. Just be­cause pro­gramma­bil­i­ty is the mag­ic smoke of com­put­ing does­n't mean we should be spooked by the ghost in the ma­chine or hes­i­tant to con­fer its pow­er up­on our cus­tomer­s.

Oh yes. Li­braries rule, and when there is no such thing as the li­brary you need, it's the worst po­si­tion to be in.

Don't think of AT­LAST as FORTH. Don't think of it as a lan­guage at al­l. The best way to think of AT­LAST is as a li­brary rou­tine that gives you pro­gramma­bil­i­ty, in the same sense oth­er li­braries pro­vide file ac­cess, win­dow man­age­men­t, or graph­ics fa­cil­i­ties. The whole con­cept of "pro­gramma­bil­i­ty in a can" is odd­--it took me two years from the time I first thought about it un­til I re­al­ly got my end ef­fec­tor around it and crushed it in­to sub­mis­sion.

I am prob­a­bly go­ing to use AT­LAST or some­thing sim­i­lar in a pro­gram, but the us­er will not see a forth-­like lan­guage at al­l, but a clas­si­cal Ex­cel-­like for­mu­la lan­guage which would get com­piled to the for­thish lan­guage be­hind the scenes.

Open is bet­ter. AT­LAST lets you build open pro­grams in less time than you used to spend writ­ing closed ones. Pro­grams that in­her­it their open ar­chi­tec­ture from AT­LAST will share, across the en­tire prod­uct line and among all hard­ware plat­forms that sup­port it, a com­mon, clean, and ef­fi­cient means of us­er ex­ten­si­bil­i­ty. The po­ten­tial ben­e­fits of this are im­mense.

In­deed. Prob­a­bly not us­ing AT­LAST, but Lua or Python or some­thing else in­stead. And stil­l, 16 years af­ter AT­LAST was re­leased to the pub­lic do­main, we are still walk­ing down this road, and not even close to the goal.

1

As they say, "Once you see a forth, you have seen a forth"

2

The "Au­todesk Thread­ed Lan­guage Ap­pli­ca­tion Sys­tem Toolk­it", by John Walk­er. Ver­sion 1.0 was re­leased in Au­gust 1995, 1.1 in Ju­ly 2002... I ex­pect 1.2 around Au­gust 2009 :-)

Sometimes, you need to do it the hard way.

You may have no­ticed no posts about Stupid­Sheet for about a week.

Well, I ran in­to the lim­i­ta­tions of the for­mu­la pars­er I was do­ing us­ing Ape­ri­ot. I just could­n't make it parse this:

A1=IF(A2=B2,1,0)

So, I spent the next week try­ing one pars­ing pack­age for Python a day un­til I could find one I un­der­stood and could make it parse that ex­am­ple.

I must say it was ed­u­ca­tion­al.

So, now the pars­er is based on PLY which is pret­ty much Lex+Y­ACC with a (s­light­ly more) python­ic syn­tax, and it work­s.

Yes, it's a bit hard­er, but by try­ing to do things sim­ply I was lim­it­ing my­self too much, and, per­haps un­der­es­ti­mat­ing my­self.

I am a pret­ty smart guy, there is no rea­son I can't un­der­stand these things.