text:
Print, Increment, Decrement, Alias - Interpret Prindeal
Prindeal (pronounced prin-dee-al) is a new esoteric programming language that only has four commands: print, increment, decrement, and alias. Despite its minimalism, complex mathematical operations can be done in Prindeal by cleverly combining the four commands.
Your task in this code golf challenge is to write the shortest program that can run Prindeal code.
The spec is long but I've tried to make it as clear as possible and I believe that if you make the effort to learn Prindeal you'll find it to be quite elegant!

Intrepreting Prindeal
Preprocessing
Before a Prindeal program can be interpreted these things need to be removed from it in this order:

Anything after a # sign to the end of the line it's on, plus the # itself. (These are comments.)
Trailing whitespace on any line.
Completely empty lines.

For example, the Prindeal program
p cat #The next line has 7 trailing spaces.
p dog

#p mouse

would be preprocessed into
p cat
p dog

From here on we'll assume this preprocessing step has been done.
Variables
We quickly need to define variables before showing how they are used.
Variables (and references to variables) are what are passed into the arguments of Prindeal commands. Variables are always global, so modifications to a variable, no matter where they occur, are reflected everywhere.
Each variable holds a non-negative arbitrary-precision integer (0, 1, 2, 3, ...). Variables do not need to be pre-initialized - they always start with the value 0 the first time they are used or called for.
A variable name may be any non-empty string of alphanumerics and underscores that does not start with a digit - [a-zA-Z_][0-9a-zA-Z_]* in regex. They are case sensitive, so spiny_lumpsuck3r and Spiny_lumpsuck3r are different variables.
Execution
Prindeal is an imperative programming language. When a Prindeal program is run its statements are executed from top to bottom in order and then the program ends.
Every non-indented line in a Prindeal program is a statement that involves the execution of a single command which may or may not take arguments.
Indented lines only occur after alias commands. Specifically, exactly three lines indented with single spaces occur after every alias command  and are considered a part of it. So alias statements are really four lines long. (They could be one line, four is merely more readable.)
Non-alias Statements
With the exception of alias, every statement in a Prindeal program has the form:
[command name] [argument 1] [argument 2] [argument 3] ...

There may be an arbitrary number of arguments (including none at all). Each argument is always a variable or (as we'll see when discussing alias) a reference to a variable.
Once done executing, each statement is flagged as either a failure or success depending on if errors were encountered or not. (This only really matters when we get around to using alias.)
The built-ins print, increment, and decrement are statements with the above form. Here is what they do:

print has command name p and takes one argument. It prints the name of the variable passed in and its value (in decimal) separated by " = ", then a newline. It is always flagged as a success.
For example, the Prindeal program
p _MyVariable_321
p screaming_hairy_armadillo

would output
_MyVariable_321 = 0
screaming_hairy_armadillo = 0

because all variables start at 0. (The spaces before and after the equals sign are required.)
increment has command name i and takes one argument. It increments the value of the variable passed in by 1. It is always flagged as a success..
For example, the program
i alpaca
p alpaca
i alpaca
p alpaca

would output
alpaca = 1
alpaca = 2

Note how alpaca was incremented from 0 to 1 even though it had never been accessed before.
decrement has command name d and takes one argument. If the variable passed in is nonzero its value is decremented by 1 and the statement is flagged as a success. If the variable passed in is 0 then nothing is done and the statement is flagged as a failure.
For example, the program
i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita

would output
malamute = 1
malamute = 0
malamute = 0
akita = 0

Notice that decrementing a variable with value 0 is the only way to produce a failure.

The alias Statement and Aliased Commands
The alias command has a special syntax and is the most powerful because it can be used to define new commands. The alias command name is a and an alias statement has the form:
a [name of new command]
 [statement A]
 [statement B]
 [statement C]

Where each [statement X] represents any non-alias statement, i.e. something with the form [command name] [argument 1] [argument 2] [argument 3] ....
The aliased command's name [name of new command] may be any non-empty string of alphanumerics and underscores that does not start with a digit - [a-zA-Z_][0-9a-zA-Z_]* in regex.
(This is the same set of names as variables but aliased commands and variables are different things used in different places. A variable could be named the same as a command with no ill consequences.)
When an alias statement is executed, a new command is added alongside the original four p i d a commands. The new command can be used as the [command name] in statements and called with arguments just like any other non-alias command.
When a statement with an aliased command name is executed, exactly two more statements from its original alias statement are run:

[statement A] is always run
[statement B] is run if [statement A] was a success
[statement C] is run if [statement A] was a failure

Statements A, B, and C are always run lazily, i.e. they are evaluated on the fly at the time they are run.
When done executing, the aliased command is flagged with the same success or failure flag as statement B or C, whichever one was executed. (alias statements themselves do not need to be flagged since they cannot occur within themselves.)

Alias Example 1
Say we want a new command that increments the variable frog twice. This alias statement achieves it:
a increment_frog_twice
 i frog
 i frog
 d frog

Statement A (i frog) is always run and always flagged as a success
  so statement B (i frog) is also always run and the variable frog
  is thus incremented by 2. The increment_frog_twice command is always
  flagged as a success because statement B is always run and B is
  always a success. Statement C (d frog) is never run.
So the output to
a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog

would be
frog = 0
frog = 2

We can generalize this example so that any variable can be incremented twice by giving the aliased command an argument.
Within an alias statement the positive integers 1, 2, 3, etc. represent the 1st, 2nd, 3rd, etc. arguments passed into the aliased command. (These arguments might be plain variables or references to variables themselves.) These numbers can only appear within the arguments of statement A, B, and C in an alias statement. It doesn't make sense for them to appear elsewhere.

Alias Example 2
This generalizes the last example - any variable passed into increment_twice will be incremented by 2 because 1 is a reference to the first argument passed in:
a increment_twice
 i 1
 i 1
 d 1 #never reached
p toad
increment_twice toad
p toad

The output of this program would be
toad = 0
toad = 2

We could then alias another command that takes in two arguments and calls increment_twice on both of them:
a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck

The output here would be
platypus = 2
duck = 2

It's important to realize that aliased commands can be recursive, as this is where their true power lies. For example, we can make a command that sets any variable passed in to 0:

Alias Example 3
The set_to_zero command takes one argument and sets its variable to 0 and is flagged as a success when done:
a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx

The output of this program would be
oryx = 3
oryx = 0

What's happening is that when set_to_zero oryx is run, d 1 successfully decrements oryx from from 3 to 2, then set_to_zero 1 is called, which is the same as calling set_to_zero oryx again. So the process repeats until d 1 is a failure, stopping the recursion and increment the _dummy_ variable so a success is produced.

Challenge
Write a program that can execute Prindeal code exactly as described above. Take the Prindeal code in via stdin, the command line, or as a text file. Print the Prindeal program's output to stdout or your language's closest alternative.
Alternatively, you can write a function that takes in the code as a string and prints or returns the output string.
Additionally, you can assume that:

The input Prindeal code will only contain newlines and printable ASCII and (optionally) that it ends with an empty line.
The input code will be valid Prindeal - well formed and syntactically correct.
Running the code will not produce any infinite loops nor any invalid references to commands that have not been defined or arguments that have not been given.
The command names p, i, d, and a will never be aliased over. (You may not assume that variables will not have these names.)

Also, it doesn't matter if your variable values aren't truly arbitrary-precision integers as only numbers less than about 1000 will be tested. It's also alright if you language has recursion limits (such as Python) that more complex Prindeal programs might encounter as long as the test program below works.
Test Program
Here is a large Prindeal program that builds up the operations of addition, multiplication, and exponentiation through the use of dummy variables (starting with _ by convention) and many helper aliases:
#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

(If you're playing around with this code be aware that many of the commands will fail if the same variable is given multiple times as an argument. This can easily be fixed but the resulting code is longer.)
Your Prindeal interpreter should be able to produce the exact output:
A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

Scoring
The shortest code in bytes wins. Tiebreaker goes to earlier submission.
Brownie Bonus: Write a cool program in Prindeal. I implemented addition and multiplication, can you do subtraction or division?

Oh man, I think for once I'll leave the Pyth alone, and pull out a Lisp! One question - functions and variables live in entirely different namespaces,  right? So I can increment p, and then p p, which would print 1, right?

@orlp Correct. (There are some notes about that in there.)

I can't be the only one who thinks PRNDL when I see the language name.

Is there a maximum number of arguments that will be passed to an aliased command?

@ZachGates Nope

So, potentially, you could pass a few thousand arguments? Fun. :P @Calvin'sHobbies

@ZachGates Yes, though I won't be testing that. (It's fine if your interpreter is limited to 2^32 arguments or whatever :P)

I started to write this in C++.  Just the includes needed for map, vector, iostream, string, sstream, utility (and a couple others) exceeded the size of the shortest entry...

Have you considered making it so the parameters that are passed to an aliased command could be command names or variable names?  Then the numbers inside the alias command could be used instead of commands or arguments.  It kind of gives you function pointers.

I've just released a Turing tarpit called Addict that's based on PRINDEAL. It's much the same, except instead of p, there's a c command which outputs as a charcode; there's also a t command for taking a charcode from input.

Pyth, 162 136 bytes
JfTmchcd\#).zKHW<ZlJI!e=T@J~+Z1=@Tk)=k0 .x=J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0,=Y.x@H=eT0?qN\pps[Td\=dYb)?xGN?qN\iXHThY?YXTH_1=k1XKT:JZ=+Z3

Demonstration.
Golfed out 26 characters by inlining variables and changing from I and E based control flow to ? and .x based control flow.
For the first time ever, I ran out of variables in Pyth. Every single variable in Pyth (bdkGHNTY and JK) was in use, and I wanted to use b as a newline. Fortunaely, I was able to use N to mean two completely different things in different parts of the program, and so it still works.
Ungolfed (run with -m):
JfTmchcd\#).z
KH
W<ZlJ
  I!e=T@J~+Z1
    =@Tk)
  =k0
     .x
      =J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0
      ,
        =Y.x@H=eT0
        ?qN\p
          ps[Td\=dYb)
          ?xGN
            ?qN\i
              XHThY
              ?Y
                XTH_1
                =k1
            XKT:JZ=+Z3

I love how I still can't tell what it does even with it ungolfed...

Well, that concludes Pyth is Non-Turing-Complete...

Python 2, 600 584 397 373 bytes
This is my own golfed reference solution. Anyone is welcome to improve it or follow its logic in their own answer as long as attribution is given.
The neat part about it is that no recursion is done, so it will never have problems with Python's recursion limit. For example, Sp's Countup Prindeal program can run indefinitely.
p=filter(len,[l.split('#')[0].split()for l in input().split('\n')]);m={};v={};i=0
while i<len(p):
 s=p[i]
 if'('in`s`:s=s[f]
 n,f=s[0],0
 if n in m:a,b,c=([s[int(g)]if g.isdigit()else g for g in t]for t in m[n]);p=[a,(b,c)]+p[i+1:];i=0;continue
 s=s[1]
 q=v.get(s,0)
 if'd'>n:m[s]=p[i+1:i+4];i+=3
 elif'i'<n:print s,'=',q
 elif'd'<n:v[s]=q+1
 elif q:v[s]-=1
 else:f=1
 i+=1

It's a program that takes in the quoted program string with newlines escaped, e.g.
'p _MyVariable_321\np screaming_hairy_armadillo'.
I took various golfing cues from Sp's and Pietu's answers. Thanks guys :)

Python 3, 345 336 335 328 bytes
a=0
A={}
V={}
def f(l):
 if l[0]in"d p i":c,u=l;U=V[u]=V.get(u,0)+"pi".find(c);S=U<0;V[u]+=S;c<"p"or print(u,"=",U)
 else:d=lambda q:[w.isdigit()and l[int(w)]or w for w in A[l[0]][q]];S=f(d(1+f(d(0))))
 return S
for z in open("P"):
 l=z.split("#")[0].split()
 if"a "==z[:2]:a,s,*x=3,l[1]
 elif l*a:x+=l,;a-=1;A[s]=x
 elif l:f(l)

(-6 bytes thanks to @orlp)
Still golfing. Assumes the program is stored in a file named P.
Putting the calls to f inside the lambda d would save a few bytes, but it would make the last test case hit max recursion depth.
Some Prindeal programs
The useless subtraction program
Here is a useless subtraction program. It's useless because, even though it subtracts properly, it doesn't return success/failure accordingly.
The output should be:
a = 15
b = 6
__________ = 0
a = 9
b = 6

Countup
a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

Counts upwards and prints n forever. Could possibly work as a test for interpreter speed (beware the long tracebacks on keyboard interrupt).

Everyone on this question has missed this golf, I don't understand why. l[:(l+"#").find("#")] and all its variations can be replaced by a simple l.split('#')[0].

@orlp Was so focused on find that I forgot you could just split even if #s weren't there. Thanks :)

JavaScript (ES6), 273 258
Edit Fixed bugs and added a real test suite.
Not counting leading spaces and newlines.
Surely can be golfed a little more.
Too tired to write an explanation now, I think it's a good example of using closures to keep alive temporary values (parameters).
Test running the snippet on any EcmaScript 6 compliant browser (notably not Chrome not MSIE. I tested on Firefox, Safari 9 could go)

F=p=>(
  p=p.match(/^[^#\n]+/gm).filter(r=>r.trim(o='',v=[])),
  s={
    '':_=>1,
    p:a=>o+=a+` = ${v[a]||0}\n`,
    i:a=>v[a]=-~v[a],
    d:a=>v[a]&&v[a]--,
    a:(n,j)=>s[n]=(u,t,a)=>x(p[!x(p[j+1],0,a,1)+j+2],0,a,1)
  },
  p.map(x=(r,i,w,l,a=r.split(/ +/).slice(l).map(x=>-x?w[x]:x))=>s[a[0]](a[1],i,a)),
  o
)

// TEST

$('#O tr').each(function() {
  var $cells = $(this).find('td')
  var prg = $cells.eq(0).text()
  console.log(prg)
  var output = F(prg)
  $cells.eq(1).text(output)
})
#O td { vertical-align:top; white-space: pre; border: 1px solid #888; font-family:monospace }

Program	Outpout

p _MyVariable_321
p screaming_hairy_armadillo

i alpaca
p alpaca
i alpaca
p alpaca

i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita

a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog

a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck

a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx

#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

I've added some more comments to the test program and it looks like they made your code not work.

@Calvin'sHobbies a first, quick patch

C#6, 653 bytes
Here's my entry, amidst a sea of Python...
class P{string[]l;string r="";Dictionary<string,int>v=new Dictionary<string,int>();Dictionary<string,int>s=new Dictionary<string,int>();public string R(string t){l=t.Split('\n');for(int i=0;i<l.Length;i++){var z=l[i].Split(' ');if(z[0]=="a"){s.Add(z[1],i);i+=3;}else E(i, null);}return r;}bool E(int n,string[]p){var z=l[n].Split(' ');var a=z.Skip(1).Select(x=>Char.IsDigit(x[0])?p[int.Parse(x)-1]:x).ToArray();if(a.Length>0&&!v.ContainsKey(a[0]))v[a[0]]=0;if (z[0]=="p")r+=$"{a[0]} = {v[a[0]]}\n";else if(z[0]=="i")v[a[0]]++;else if(z[0]=="d")if(v[a[0]]>0)v[a[0]]--;else return false;else{var y=s[z[0]];return E(y+1,a)?E(y+2,a):E(y+3,a);}return true;}}

Expanded and commented:
class Prindeal
{
    string[] lines;
    string result = "";
    Dictionary<string, int> variables = new Dictionary<string, int>();
    Dictionary<string, int> statements = new Dictionary<string, int>();

    public string Run(string text)
    {
        lines = text.Split('\n');

        for (int i = 0; i < lines.Length; i++)
        {
            // Split on spaces to get the statement and any arguments
            var z = lines[i].Split(' ');

            // Are we defining a new statement?
            if (z[0] == "a")
            {
                // Add to the statements dictionary, step over definition statements
                statements.Add(z[1], i);
                i += 3;
            }
            else
            {
                // Execute the statement
                Execute(i, null);
            }
        }

        return result;
    }

    bool Execute(int lineNumber, string[] parameters)
    {
        // Split on spaces to get the statement and any arguments
        var z = lines[lineNumber].Split(' ');

        // Parse the arguments - if it's a number, get the corresponding
        // parameter from the calling statement
        var arguments = z.Skip(1).Select(
            x => Char.IsDigit(x[0]) ?
            parameters[int.Parse(x) - 1] :
            x)
            .ToArray();

        // If the first argument isn't already in the variables dict, add it
        if (arguments.Length > 0 && !variables.ContainsKey(arguments[0])) variables[arguments[0]] = 0;

        // Print statement, using string interpolation
        if (z[0] == "p")
            result += $"{arguments[0]} = {variables[arguments[0]]}\n";
        // Increment statement
        else if (z[0] == "i")
            variables[arguments[0]]++;
        // Decrement statement
        else if (z[0] == "d")
            if (variables[arguments[0]] > 0)
                variables[arguments[0]]--;
            else
                return false;
        else
        {
            // Get the line number to jump to
            var y = statements[z[0]];

            // Execute A ? B : C
            return Execute(y + 1, arguments) ? Execute(y + 2, arguments) : Execute(y + 3, arguments);
        }

        // If we reach this point, it's from a 'p', 'i' or 'd' statement which has succeeded
        return true;
    }
}

To use it, simply instantiate the class and call the R() method, for example:
string prindealText = new StreamReader("prindeal.txt").ReadToEnd();
Console.WriteLine(new P().R(prindealText));

Common Lisp, 758 646 619
(progn(set-macro-character #\#(get-macro-character #\;))(setf(readtable-case *readtable*):invert)(#3=defun v(s)(if(boundp s)(eval s)0))(#3# i(s)(set s(1+ (v s))))(#3# d(s)(and(plusp(v s))(set s(1-(v s)))))(#3# p(s)(format t"~A = ~A~%"s(v s)))(defmacro a(n . p)`(#3#,(cadr n)(&rest g)(if,@p)))(#3# k(s)(typecase s(integer`(nth,(1- s)g))(symbol `',s)(t(list*(car s)(mapcar 'k(cdr s))))))(#3# r()(prog(l p q)$(setf p()l(make-string-input-stream(or(read-line()()())(return))))@(when(setf p(read l()()))(push p q)(go @))(if q(return(k(reverse q)))(go $))))(do ((x(r)(r)))((not x))(eval(if(eq(car x)'a)`(,@x,(r),(r),(r))x))))

Put this in file.lisp and call for example sbcl --script file.lisp; input is read from the standard input stream.
This version parses a superset of Prindeal: without not much difficulties, you can access all Common Lisp from a Prindeal source. I consider this a feature of the intepreter.
Commented version
;; copy-readtable is only used during development, so that I do not
;; mess with my running environment. The real code starts with the
;; progn below, which is superfluous of course inside a let.
(let ((*readtable* (copy-readtable)))

  ;; I use PROGN in the golfed version so that I can have the whole
  ;; program as a unique tree. This allows me to define reader
  ;; variables like #3=defun in order to gain a few bytes by writing
  ;; #3# instead of defun. Reader variables are removed in
  ;; this human-friendly version.
  (progn
    ;; Let # point to the same reader function as ;
    ;; Of course, ; is still usable as a comment delimiter
    (set-macro-character #\#
                         (get-macro-character #\;))

    ;; :invert does what is necessary to enable case-sensitive reading
    ;; and printing of symbols
    (setf (readtable-case *readtable*) :invert)

    ;; value of symbol, or zero
    (defun v(s)(if(boundp s)(eval s)0))

    ;; increment
    (defun i(s)(set s(1+ (v s))))

    ;; decrement
    (defun d(s)(and(plusp(v s))(set s(1-(v s)))))

    ;; print
    (defun p(s)(format t"~A = ~A~%"s(v s)))

    ;; alias: wrap an "if" inside a "defun".
    ;; YES, that means you can redefine ANY lisp function with "a" !
    ;; A safer version would properly intern symbols in a dedicated package.
    ;;
    ;; Notice the G variable.  We take advantage of the "unhygienic"
    ;; (what a bad adjective) nature of macros to create a context
    ;; where G is bound to the argument list. The same G is referenced
    ;; implicitely later.
    (defmacro a(n . p)`(defun,(cadr n)(&rest g)(if,@p)))

    ;; Canonicalize expressions:
    ;;
    ;; - if s is a symbol, return s quoted. All functions manipulate
    ;; symbols in order to allow the undeclared use of variables. With
    ;; symbols, we can check for boundness.
    ;;
    ;; - if s is an integer, then we are inside an alias definition. The
    ;; integer is replaced by an access to the s'th element of the
    ;; implicit argument list G using (nth (1- s) g). G will be bound
    ;; when the expressions is injected in the defun corresponding to
    ;; the alias, or else an error will be signaled: either because G
    ;; is unbound, or because you defined a variable named G which is
    ;; by construction not a list. Since we do not sanitize properly
    ;; the input, you could bind G globally to a list, but that would be
    ;; nasty.
    ;;
    ;; - Finally, if s is a list, apply k to all but the first
    ;; elements of s.  The first element is a symbol but we do not
    ;; need to quote it because we want to call the function
    ;; associated with the symbol. Due to the Lisp-2-ness
    ;; of Common Lisp, functions and variables can coexist
    ;; with the same name.
    ;;
    (defun k(s)(typecase s
                 (integer`(nth,(1- s)g))
                 (symbol`',s)
                 (t(list*(car s)(mapcar #'k(cdr s))))))

    ;; Reader function
    (defun r()
      (prog (l ; current line, as an input-stream reading a string
             p ; current read form
             q ; whole line and return value, as a list
             )

         ;; PROG includes an implicit TAGBODY. Below, $ and @ are
         ;; labels for GO statements (gotos).

       $ (setf
          ;; emtpy p
          p ()

          ;; Read a whole line and if we do not fail, build an input
          ;; stream to read from it.
          l (make-string-input-stream
             (or (read-line()()()) ;; try to read a line,
                 (return)          ;; but return from prog if we reach
                                   ;; the end of file.
                 )))
       @ (when (setf p (read l()()))
           ;; Read a lisp expression, put it in p and if p is not nil
           ;; push it into q.  A nil could happen at the end of the
           ;; line or if someone (you know who) inserted an empty list
           ;; in the file being read.
           ;;
           ;; Thanks to the readtable which now handles comments
           ;; and spaces for us, nothing needs to be done here to
           ;; preprocess the input.

           (push p q) (go @))

         ;; If we read an empty line, q can be nil. In this case, go
         ;; back to $ and read another line. If q is not nil, reverse
         ;; it (we pushed, remember), canonicalize it and return the
         ;; result.
         (if q (return(k(reverse q))) (go $)))
      )

    ;; Read/eval loop.  When reading "(a name)", we read the three
    ;; next lines and append them to the first so that it builds a
    ;; call the the alias definition macro a. Otherwise, just eval x.
    (do((x(r)(r))((not x))
      (eval (if (eq(car x'a))
                `(,@x,(r),(r),(r))
                x)))))

Example
~$ sbcl --script file.lisp < testfile

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

If we replace eval by print in the read/eval loop, then we can see what is being evaluated:
(a 's (i '_) (d '_) (d '_))
(a 'f (d '_) (d '_) (d '_))
(a 'z (d (nth 0 g)) (z (nth 0 g)) (s))
(a 'n (z (nth 0 g)) (i (nth 0 g)) (s))
(a 'move (moveH (nth 0 g) (nth 1 g)) (move (nth 0 g) (nth 1 g)) (s))
(a 'moveH (d (nth 0 g)) (i (nth 1 g)) (f))
(a 'dupe (dupeH1 (nth 0 g) (nth 1 g) (nth 2 g))
   (dupe (nth 0 g) (nth 1 g) (nth 2 g)) (s))
(a 'dupeH1 (d (nth 0 g)) (dupeH2 (nth 1 g) (nth 2 g)) (f))
(a 'dupeH2 (i (nth 0 g)) (i (nth 1 g)) (s))
(a 'copy (z (nth 1 g)) (copyH (nth 0 g) (nth 1 g)) (s))
(a 'copyH (dupe (nth 0 g) (nth 1 g) '_copy) (move '_copy (nth 0 g)) (s))
(a 'addTo (copy (nth 1 g) '_add) (move '_add (nth 0 g)) (s))
(a 'add (z (nth 0 g)) (addH (nth 0 g) (nth 1 g) (nth 2 g)) (s))
(a 'addH (addTo (nth 0 g) (nth 1 g)) (addTo (nth 0 g) (nth 2 g)) (s))
(a 'mul (mulH1 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 2 g)) (s))
(a 'mulH1 (z (nth 0 g)) (copy (nth 1 g) '_mul) (s))
(a 'mulH2 (mulH3 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 1 g)) (s))
(a 'mulH3 (d '_mul) (addTo (nth 0 g) (nth 1 g)) (f))
(a 'mulBy (mul '_mulBy (nth 0 g) (nth 1 g)) (copy '_mulBy (nth 0 g)) (s))
(a 'pow (powH1 (nth 0 g) (nth 2 g)) (powH2 (nth 0 g) (nth 1 g)) (s))
(a 'powH1 (n (nth 0 g)) (copy (nth 1 g) '_pow) (s))
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))
(a 'powH3 (d '_pow) (mulBy (nth 0 g) (nth 1 g)) (f))
(p 'A)
(p 'B)
(p 'C)
(n 'A)
(n 'B)
(add 'C 'A 'B)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(add 'B 'A 'C)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(mul 'd 'B 'C)
(p '____)
(p 'd)
(mulBy 'd 'B)
(p '____)
(p 'd)
(d 'A)
(mulBy 'd 'A)
(p '____)
(p 'd)
(pow 'A 'C 'B)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(pow 'A 'B 'C)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(pow 'C 'A 'B)
(p '____)
(p 'A)
(p 'B)
(p 'C)

Macroexpansion
If we pick the following alias definition:
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))

... we can see references to a variable named g which is nowhere to be found in the lexical scope. But after macroexpansion, here is the actual code  being evaluated:
(defun powH2 (&rest g)
  (if (powH3 (nth 0 g) (nth 1 g))
      (powH2 (nth 0 g) (nth 1 g))
      (s)))

Now, g refers to the argument list of the function being defined.

Python 2, 486 bytes
This is the reference solution which I golfed more (currently -98 bytes).
import sys;sys.setrecursionlimit(2000)
def r(s):
 n=s[0]
 if n in A:f=lambda i:r([s[int(t)]if'0'<t[0]<':'else t for t in A[n][i]]);return f(1+(f(0)or 0))
 k=s[1]
 if'i'<n:print k,'=',V.get(k,0)
 elif'd'<n:V[k]=-~V[k]if k in V else 1
 elif'a'<n:
    if~-(k in V)or V[k]<1:return 1
    V[k]-=1
 else:A[k]=s[2:]
A={};V={};c=filter(bool,([l,l[:l.find('#')]]['#'in l]for l in input().split('\n')))
while c:
 s=c[0].split();c=c[1:]
 if'a'!=s[0]:r(s)
 else:r(['a',s[1]]+map(str.split,c[:3]));c=c[3:]

Changes (that I recall):

automatic boolean-integer conversion ([l,l[:l.find('#')]]['#'in l]).
set or increment in one statement (V[k]=-~V[k]if k in V else 1)
more aliases to longer expressions (k=s[1])
no counter in the main loop, clearing the input list instead
print automatically adding spaces (print k,'=',V.get(k,0))
checking digits 1-9 ('0'<t[0]<':')
flipping the return values of r around to save returns
removing repetition of slicing and splitting (map(str.split,c[:3])))

C++, 752 bytes
Thanks to @ceilingcat for some very nice pieces of golfing - now even shorter (yet again!)
This one is C++ - as idiomatic as I could make it.
That means making it more C++-ish and less C-ish.
That also means it is bigger than the equivalent C program.
I think C++ rivals Java for the most verbose standard library.
#import<bits/stdc++.h>
#define a first
#define c(s);else if(B==#s)
#define e(n)(n=regex_replace(n,regex{"^ *(.*?) *(#.*)?$"},"$1")).size()
#define f(n)for(;getline(cin,n),!e(n););
#define i p.top().a
#define j p.size()
#define k n[o[0]]
#define U;using
U namespace std;U g=string;U h=istream_iterator<g>U s=vector<g>;map<g,s>m;map<g,int>n;stack<pair<pair<int,s>,s>>p;main(int v){for(g X,Y,Z;getline(cin,X);)if(e(X))for(p.push({{0,{X,"",""}},{}});bool z=j;){g B;s C,o;copy(h(stringstream(i.second[i.a])>>B),h(),back_inserter(C));for(g x:C)o.push_back((v=atoi(&x[0]))>0?p.top().second[v-1]:x);if(0)c()c(p)cout<<o[0]+" = "<<k<<'\n'c(i)k++c(d)k-=z=k c(a){f(X)f(Y)f(Z)m[o[0]]={X,Y,Z};}else{p.push({{0,m[B]},o});continue;}while(j&&i.a)p.pop();j?i.a-=~!z:0;}}

Try it online!
Below is the original.  If anyone can think of a way to make it more idiomatic and shorter at the same time please let me know.
#include <array>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <stack>

typedef std::vector<std::string> List;
typedef std::pair<std::string, List> Statement;
typedef std::array<std::string, 3> Alias;
typedef std::pair<long, Alias> IndexedAlias;
typedef std::pair<IndexedAlias, List> Item;

std::map<std::string, Alias> aliases;
std::map<std::string, long> variables;
std::stack<Item> stack;
std::regex re("^ *(.*?) *(#.*)?$");

int main()
{
    std::string line, line1, line2, line3;
    while (std::getline(std::cin, line)) // control-Z to exit
    {
        line = std::regex_replace(line, re, "$1");
        if (line.empty()) continue;
        stack.push(Item{ { 0, { { line, "", "" } } }, {} });

        bool flag;
        while (!stack.empty())
        {
            Statement statement;
            std::istringstream ss(stack.top().first.second[stack.top().first.first]);
            ss >> statement.first;
            std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>(), std::back_inserter(statement.second));

            List arguments;
            std::transform(std::begin(statement.second), std::end(statement.second), std::back_inserter(arguments),
                [](std::string arg){ int i = atoi(arg.c_str()); return i > 0 ? stack.top().second[i - 1] : arg; });

            flag = true;
            if (statement.first == "")
                ;
            else if (statement.first == "p")
                std::cout << arguments[0] << " = " << variables[arguments[0]] << std::endl;
            else if (statement.first == "i")
                variables[arguments[0]]++;
            else if (statement.first == "d")
                variables[arguments[0]] -= (flag = variables[arguments[0]]);
            else if (statement.first == "a")
            {
                do { std::getline(std::cin, line1); line1 = std::regex_replace(line1, re, "$1"); } while (line1.empty());
                do { std::getline(std::cin, line2); line2 = std::regex_replace(line2, re, "$1"); } while (line2.empty());
                do { std::getline(std::cin, line3); line3 = std::regex_replace(line3, re, "$1"); } while (line3.empty());
                aliases.insert(std::make_pair(arguments[0], Alias{ { line1, line2, line3 } }));
            }
            else
            {
                stack.push(Item{ { 0, aliases[statement.first] }, arguments });
                continue;
            }

            while (!stack.empty() && stack.top().first.first) stack.pop();
            if (!stack.empty()) stack.top().first.first += 1 + !flag;
        }
    }

    std::cout << "-- Variables --" << std::endl;
    std::transform(std::begin(variables), std::end(variables), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, long>::value_type pair){ std::ostringstream ss; ss << pair.first << " = " << pair.second; return ss.str(); });
    std::cout << "-- Aliases --" << std::endl;
    std::transform(std::begin(aliases), std::end(aliases), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, Alias>::value_type pair){ std::ostringstream ss; ss << pair.first << " = [1]:" << pair.second[0] << " [2]:" << pair.second[1] << " [3]:" << pair.second[1]; return ss.str(); });
    std::cout << "---------------" << std::endl;

    return 0;
}

Uiua (tentative), 468 characters
Note that due to a bug in the interpreter, there is a spurious error preventing proper execution. Once the bug is fixed, I will update this answer to reflect that. Until then, I'm leaving the (tentative) in the heading.
p←⊂↯→(⊟∶□0□,)¬/+≡(|2≅!)→(↯→∶⧻).≡⊢.→(.!⊡1)!→→(⊡2)⊡1,∶
;∧(|2!⊡∶(⊂□1⊟□&p/+∺(×≅→∶∷!⊢∶⊡1.),∶&pf⊂∶" = ",p)_(⊂□1⊟□∺([∶∷□]+→(∶→≅.)!⊡1∶!⊢.)p)_(⊂⊟→□→≡(⍜'⊡1⍜!'↥0)/×≡(≥0!⊡1).∺([∶∷□]-∶→(∶→≅.)!⊡1∶!⊢.)p)_(|2↬2∶□/(⊂⊂∶@ ∷!)⊡-∶2!⊢,∶↬2∶□/(⊂⊂∶@ ∷!)⊢,∶→→;∺(|2⍜'↘1∺(|2□⍣(!⊡parse)(→;;)!)⊜□≠,@ !)→,↘1⊡∶!⊡2,⊗∶≡⊢!⊡2,⊢,)⊗∶["p""i""d"]!⊢,∶⊜□≠@ .!∶)⊂{1[{"1"0}]}□→(▽¬∵(|1↥=@ ∶=@a.⊢!).)≡(⍜'↘1(∵⍜!(↘1))⍜⊢(⍜!(↘2)))⊜·▽∵(4;).+1⇡÷4⧻.▽∵(|1↥=@ ⊢∶≅"a ".↙2!)..▽↧1∵⧻.∵⍜!(⇌▽\↥×≠@\r∶≠@ ..⇌▽=0\+=@#.)⊜□≠@\n.&ru@\00

This is my first Uiua program of more than a couple dozen characters, so I'm sure there's lots of places I could golf it more effectively. It was a good opportunity to practice the language, though :)
Non-minified version
# preexec state_alias_array command -> state_array command_arg alias_array
preexec ← (
  ⊡1,∶ # put state on top
  !→→(⊡2) # get aliases (for later)
  →(.!⊡1) # get variable name (put two copies on stack for later)
  ≡⊢. # get list of current variable names
  ¬/+≡(|2 ≅!) →(↯→∶⧻). # test if we need to add a new variable
  ⊂↯→(⊟∶□0□,) # add variable if necessary
)

# exec<T> state_alias_array command -> state_alias_array
execp ← (
  preexec
  &pf⊂∶" = ", # print "varName = "
  &p/+∺(×≅→∶∷!⊢∶⊡1.),∶ # print "varValue\n"
  ⊂□1⊟□
)
execi ← (
  preexec
  ∺([∶∷□]+→(∶→≅.)!⊡1∶!⊢.) # increment the relevant variable
  ⊂□1⊟□ # reform state_alias_array
)
execd ← (
  preexec
  ∺([∶∷□]-∶→(∶→≅.)!⊡1∶!⊢.) # decrement the relevant variable
  /×≡(≥0!⊡1). # check if <0
  →≡(⍜'⊡1⍜!'↥0) # reset back up to 0
  ⊂⊟→□ # reform state_alias_array
)
execcall ← (|2
  ⊢, # get alias name
  ⊗∶≡⊢!⊡2, # get index of call
  ↘1⊡∶!⊡2, # get subcommands
  →,
  ∺(|2
    ⊜□≠,@ ! # split box"thing 1 2" into [box"thing" box"1" box"2"]
    ⍜'↘1∺(|2 □⍣(!⊡parse)(→;;)!) # turn the 1 and 2 into first and second arguments
  )
  →→; # original call no longer necessary
  □/(⊂⊂∶@ ∷!)⊢,∶ # join [box"i" box"dog"] into box"i dog"
  ↬2∶ # call first
  ⊡-∶2!⊢,∶ # select second or third based on success
  □/(⊂⊂∶@ ∷!) # join [box"i" box"dog"] into box"i dog"
  ↬2∶
)

execline ← (|2
  ∶⊜□≠@ .!∶ # split command
  !⊡∶execp_execi_execd_execcall⊗∶["p""i""d"]!⊢, # dispatch correct command
)

&ru@\00

⊜□≠@\n. # split lines
∵⍜!(
  ▽=0\+=@#. # remove comments
  ⇌▽\↥×≠@\r∶≠@ ..⇌ # remove trailing whitespace
)
▽↧1∵⧻. # remove blank lines

▽∵(|1 ↥=@ ⊢∶≅"a ".↙2!).. # get alias definitions
⊜· ▽∵(4;).+1⇡÷4⧻. # separate out each alias
≡(
  ⍜⊢(⍜!(↘2)) # remove alias decl
  ⍜'↘1(∵⍜!(↘1)) # remove indentation
)
→(▽¬∵(|1 ↥=@ ∶=@a.⊢!).) # remove alias definitions from command list
⊂{1 [{"123illegalvariable" 0}]}□ # group last success, state array and alias array
∧execline # exec all instructions
;

Python 3, 1322 bytes
Golfed:
import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
 N,O,F=0,{},{}
 def __init__(S,c):
  S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
  while S.N in S.E:S.X(S.E[S.N])
 def V(S, v, y, z=0):
  if re.match("[\w_][\d\w_]*",v):
   if not v in y:
    if z is not None:y[v]=z
    else:return False
   return True
  return False
 def A(S):S.N+=1
 def P(S,v):
  if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
  return False
 def I(S,v):
  if S.V(v, S.O):S.O[v]+=1;return True
  return False
 def D(S,v):
  if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
  return False
 def L(S,v):
  e=[]
  if S.V(v,S.F,e):
   for i in range(3):S.A();e.append(S.E[S.N].lstrip())
   return True
  return False
 def C(S,c,v):
  def R(Z,v):
   for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
   return Z
  Q,m,f=map(lambda l:R(l,v),S.F[c])
  if S.X(Q,False):return S.X(m,False)
  return S.X(f,False)
 def X(S,Z,C=True):
  u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
  if u:
   c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
   if S.V(c,S.F,None):
    T=S.C(c, v)
    if C:S.A()
   elif S.V(c,S.B,None):
    T=S.B[c](*v)
    if C:S.A()
   else:return False
   return T
  return False

Ungolfed:
import re

class Prindeal:
    iline = 0
    local = {}
    udef = {}
    content  = {}

    def __init__(self, c):
        self.built = {
            "p": self.print,
            "i": self.increment,
            "d": self.decrement,
            "a": self.alias,
        }
        self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
        while self.iline in self.content:
            self.execute_line(self.content[self.iline])

    def validate_name(self, varname, stack, default=0):
        if re.match("[\w_][\d\w_]*", varname):
            if not varname in stack:
                if default is not None:
                    stack[varname] = default
                else:
                    return False
            return True
        return False

    def advance_stack(self):
        self.iline += 1

    def print(self, varname):
        if self.validate_name(varname, self.local):
            print("{0} = {1}".format(varname, self.local[varname]))
            return True
        return False

    def increment(self, varname):
        if self.validate_name(varname, self.local):
            self.local[varname] += 1
            return True
        return False

    def decrement(self, varname):
        if self.validate_name(varname, self.local) and self.local[varname] > 0:
            self.local[varname] -= 1
            return True
        return False

    def alias(self, aliasname):
        indexed_lines = []
        if self.validate_name(aliasname, self.udef, indexed_lines):
            for i in range(3):
                self.advance_stack()
                indexed_lines.append(self.content[self.iline].lstrip())
            return True
        return False

    def execute_alias(self, cmd, variables):
        def parse_args(line, variables):
            for i in re.findall("\s(\d+)", line):
                line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
            return line
        init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
        if self.execute_line(init, False):
            return self.execute_line(success, False)
        return self.execute_line(failure, False)

    def execute_line(self, line, cont=True):
        valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
        if valid_execution:
            cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
            variables = list(filter(None, variables.split(' ')))
            if self.validate_name(cmd, self.udef, None):
                temp = self.execute_alias(cmd, variables)
                if cont:
                    self.advance_stack()
            elif self.validate_name(cmd, self.built, None):
                temp = self.built[cmd](*variables)
                if cont:
                    self.advance_stack()
            else:
                return False
            return temp
        return False

Usage:
P(c)

Where c is the text content.
Examples:
Single-line strings are accepted:

P("p cat")
P("p dog\ni dog\np dog")

Multi-lined strings are also accepted:
P("""
p dog
i dog
p dog
""")

Or:
P("""p dog
i dog
p dog""")

Etc.
Notes:
This works correctly for all test cases, but reaches the recursion limit on:
pow C A B   #C = A ^ B = 9 ^ 3 = 729

Hence the sys.setrecursionlimit(2000).

It'll use up some bytes but couldn't you use sys.setrecursionlimit() to get this working properly with the pow alias?

I could, but OP stated that languages like Python (that have recursion limits) are accepted as-is. However, I will add the fix if requested by OP. @Corwin

Fair enough. Missed that in the spec. @ZachGates

Haskell, 1009
I did my best to golf it; my ungolfed code consisted of over 3,000 characters. At this point I can't remember what all the functions are doing so golfing it more mean guessing what will break it and what won't.
import qualified Data.Map as M
import Control.Monad.State.Lazy
import Data.List
type A=M.Map String
data P=P(A Int)(A([String]->StateT P IO Int))
a f=evalStateT f(P M.empty$M.fromList[("i",\(b:_)->(+1)%b),("d",\(b:_)->pred%b),("p",\(b:_)->i b>>= \v->liftIO(putStrLn$b++"="++show v)>>q 1)])
e(k:l)=do{(P v a)<-get;put.P v$M.insert k(m l)a;q 1}
g t s f= \a->t a>>= \b->if b>0then s a else f a
f%k=f<$>i k>>= \v->if v<0then k#0>>q 0else k#v>>q 1
i k=get>>= \(P v _)->q$M.findWithDefault 0 k v
k#v=get>>= \(P b a)->put$P(M.insert k v b)a
l k=get>>= \(P _ a)->q$a M.!k
f s=let(f:a)=r s in($a)<$>l f>>=id
m(t:s:f:_)=g(k t)(k s)(k f)
k s=let(f:b)=r s in\a->($(map((\y z->if all(\c->c>'/'&&c<':')z then y!!(read z-1)else z)a)b))<$>l f>>=id
n=dropWhileEnd(==' ').takeWhile(not.(=='#')).dropWhile(==' ')
o[]=[]
o(l:ls)|(head.r$l)=="a"=(l:take 3 ls):(o$drop 3 ls)|1>0=[l]:o ls
p s|length s>1=e$(n.tail.head$s):tail s|1>0=f.head$s
q=return
main=join$a.(\s->mapM_ p(o.filter(not.null).map n.lines$s))<$>getContents
r=words

Python - 695 688 bytes
def p(v):print v,"=",w.get(v,0)
def i(v):w[v]=w.get(v,0)+1
def d(v):
 if v in w:
<TAB>w[v]-=1
<TAB>if not w[v]:del w[v]
 else:return 1
def a(n,b,d,h):
 def g(*a):
<TAB>i=1;f=b;s=d;t=h
<TAB>for v in a:v=q+v+q;k=q+j(i)+q;f=c(f,k,v);s=c(s,k,v);t=c(t,k,v);i+=1
<TAB>y=u(t,e)if u(f,e)else u(s,e);i=1;return y
 e[n]=g
q="'";w=x={};u=eval;e={'a':a,'d':d,'i':i,'p':p};import sys;l=sys.stdin.readlines();r="";j=str;c=j.replace;sys.setrecursionlimit(2000)
for h in l:
 h = h.strip()
 if not h:continue
 l = h.split();f=l[0];n=f+"("
 if "#" in f:continue
 for g in l[1:]:
<TAB>b=g.find("#")+1
<TAB>if b:g=g[:b-1]
<TAB>if g:n+="'%s',"%g
<TAB>if b:break
 if x:x-=1;d+='"%s)",'%n
 else:x=(f=="a")*3;d=n
 if not x:d+=")\n";r+=d
exec r in e

<TAB> is a literal tab character.

APL (Dyalog Unicode), 449 422 388 383 bytes
This is a somewhat optimized APL version of a program to run the Prindeal code. It assumes that the index origin is 0 (⎕IO←0). The Prindeal program to run is in an enclosed string array P.

z
L←0
V←N←F←M←⍬
r←{⍬≡h←⍸⎕D∊⍨⊃¨t←↑⍵:t⋄t[h]←⍺[⍎¨t[h]]⋄t}
R←{⍵/⍨∊0≠⍴∘∊¨⍵}{' '(≠⊆⊢)⍵/⍨~∨\'#'=⍵}∘∊¨P
k:e↑L⌷R
L+←1
→k/⍨L<⍴R

{y}←e c;x
y←1
→((⊃c)∘≡∘,¨'pida')/p i d a
y←e c r x⌷⍨2-e c r 0⌷x←↑F[M⍳0⌷c]
→0
p:N[x],’=‘,2⊥⌽↑V[x←g c]
→0
i:V[x]←⊂{⍬≡⍵:1⋄⊃⍵:0,∇1↓⍵⋄1,1↓⍵}↑V[x←g c]
→0
d:→0/⍨~y←(,0)≢m←↑V[x←g c]
V[x]←⊂m↓⍨-(1=⍴m)⍱⊃⌽m←{⍬≡⍵:⍬⋄~⊃⍵:1,∇1↓⍵⋄0,1↓⍵}m
→0
a:M←M,1⌷c
F←F,⊂R[L+1+⍳3]
L+←3

x←g c
x←N⍳1⌷c
→0/⍨x<⍴N
N←N,1⌷c
V←V,⊂,0

The code length was a bit less until I reread the specification that requires arbitrary precision integers. I added code to provide this functionality although I'd hate to wait around for a Prindel program that requires this feature to execute. Dialog APL does have some prewritten routines ('big') to provide this functionality, However, I felt it would be a bit of a cheat to use all that extra 'hidden' code and call it an inherent part of the language.
In any case, the program consists of eight basic functions as follows:
 z - this function initializes variables, strips comments, trailing blanks and empty lines; then loops through the Prindeal program code.

 e - this executes a Prindeal statement either an inherent statement (p,i,d,a) or a defined alias. Recursive.

 g - gets a reference to a variable value (defines if as-of-yet undefined)

 r - at execution time, resolves numerical reference to arguments in alias functions

Comments and improvements are welcomed. I first dabbled in APL in the late 60s and early 70s. Life took me in another direction, but apparently I never lost my interest in the language. I recently took a look at the state of the language (via Dialog) and found that what was a powerful language back in the day had only grown in complexity and capability. I'm using some of these code golf challenges to introduce me to the newer (to me) language features and have a bit of fun ... lifelong learning.
In any case, here is the output from the test program:

     z
 A = 0
 B = 0
 C = 0
 ____ = 0
 A = 1
 B = 1
 C = 2
 ____ = 0
 A = 1
 B = 3
 C = 2
 ____ = 0
 d = 6
 ____ = 0
 d = 18
 ____ = 0
 d = 0
 ____ = 0
 A = 8
 B = 3
 C = 2
 ____ = 0
 A = 9
 B = 3
 C = 2
 ____ = 0
 A = 9
 B = 3
 C = 729

```


text:
ValiDate ISO 8601 by RX
Challenge
Find the shortest regex that

validates, i.e. matches, every possible date in the Proleptic Gregorian calendar (which also applies to all dates before its first adoption in 1582) and
does not match any invalid date.

Output
Output is therefore truthy or falsey.
Input
Input is in any of 3 expanded ISO 8601 date formats – no times.
The first two are ±YYYY-MM-DD (year, month, day) and ±YYYY-DDD (year, day). Both need special-casing for the leap day. They are naively matched separately by these extended RXs:
(?<year>[+-]?\d{4,})-(?<month>\d\d)-(?<day>\d\d)
(?<year>[+-]?\d{4,})-(?<doy>\d{3})

The third input format is ±YYYY-wWW-D (year, week, day). It is the complicated one because of the complex leap week pattern.
(?<year>-?\d{4,})-W(?<week>\d\d)-(?<dow>\d)

A basic, but insufficient validity check for all three combined would look something like this:
[+-]?\d{4,}-((0\d|1[0-2])-([0-2]\d|3[01]) ↩
            |([0-2]\d\d|3[0-5]\d|36[0-6]) ↩
            |(W([0-4]\d|5[0-3])-[1-7]))

Conditions
A leap year in the Proleptic Gregorian calendar contains the leap day …-02-29 and thus it is 366 days long, hence …-366 exists. This happens in any year whose ordinal number is divisible by 4, but not by 100 unless it’s also divisible by 400.
Year zero exists in this calendar and it is a leap year.
A long year in the ISO week calendar contains a 53rd week, which one could term a “leap week”. This happens in all years where 1 January is a Thursday and additionally in all leap years where it’s a Wednesday. It turns out to occur every 5 or 6 years usually, in a seemingly irregular pattern.
A year has at least 4 digits. Years with more than 10 digits do not have to be supported, because that’s close enough to the age of the universe (ca. 14 billion years). The leading plus sign is optional, although the actual standard suggests it should be required for years with more than 4 digits.
Partial or truncated dates, i.e. with less than day-precision, must not be accepted.
The parts of the date notation, e.g. the month, do not have to be matched by a group that could be referenced.
Rules
This is code-golf. The shortest regex without executed code wins. Update: You may use features like recursion and balanced groups, but will be fined by a factor of 10, which the character count then is multiplied with! This is now different from the rules in Hard code golf: Regex for divisibility by 7. Earlier answer wins a tie.
Test cases
Valid tests
2015-08-10
2015-10-08
12015-08-10
-2015-08-10
+2015-08-10
0015-08-10
1582-10-10
2015-02-28
2016-02-29
2000-02-29
0000-02-29
-2000-02-29
-2016-02-29
200000-02-29
2016-366
2000-366
0000-366
-2016-366
-2000-366
2015-081
2015-W33-1
2015-W53-7
 2015-08-10

The last one is optionally valid, i.e. leading and trailing spaces in input strings may be trimmed.
Invalid formats
-0000-08-10     # that's an arbitrary decision
15-08-10        # year is at least 4 digits long
2015-8-10       # month (and day) is exactly two digits long, i.e. leading zero is required
015-08-10       # year is at least 4 digits long
20150810        # though a valid ISO format, we require separators; could also be interpreted as a 8-digit year
2015 08 10      # separator must be hyphen-minus
2015.08.10      # separator must be hyphen-minus
2015–08–10      # separator must be hyphen-minus
2015-0810
201508-10       # could be October in the year 201508
2015 - 08 - 10  # no internal spaces allowed
2015-w33-1      # letter ‘W’ must be uppercase
2015W33-1       # it would be unambiguous to omit the separator in front of a letter, but not in the standard
2015W331        # though a valid ISO format we require separators
2015-W331
2015-W33        # a valid ISO date, but we require day-precision
2015W33

Invalid dates
2015        # a valid ISO format, but we require day-precision
2015-08     # a valid ISO format, but we require day-precision
2015-00-10  # month range is 1–12
2015-13-10  # month range is 1–12
2015-08-00  # day range is 1–28 through 31
2015-08-32  # max. day range is 1–31
2015-04-31  # day range for April is 1–30
2015-02-30  # day range for February is 1–28 or 29
2015-02-29  # day range for common February is 1–28
2100-02-29  # most century years are non-leap
-2100-02-29 # most century years are non-leap
2015-000    # day range is 1–365 or 366
2015-366    # day range is 1–365 in common years
2016-367    # day range is 1–366 in leap years
2100-366    # most century years are non-leap
-2100-366   # most century years are non-leap
2015-W00-1  # week range is 1–52 or 53
2015-W54-1  # week range is 1–53 in long years
2016-W53-1  # week range is 1–52 in short years
2015-W33-0  # day range is 1–7
2015-W33-8  # day range is 1–7

This question is not well-defined because the regex language is not specified.

@orlp If it’s not specified, the choice is not limited. I wrote “regex” or “RX” on purpose, so one could use dialects that allow recursion etc. (i.e. CFG, not RG).

I would strongly suggest you to limit the regex language, because it will be very sour for a contestant to work for hours on a solution only to be trivially beaten by a language that is fundamentally more powerful. If you were to limit the language to the actual CS definition of regular expressions (like DFA), then the problem becomes an interesting optimization answer.

Validating ISO-8601 dates using regular expressions is something I've actually had to do for work. But agree with orlp, I think a language is necessary here.

@orlp I will not disallow recursion etc., but put a heavy penalty on it, since there have not been any submissions yet.

Some dates in year 1582 should also be invalid, eg. 1582-10-10, as after October 4th there was immediately October 15th, also days larger than 355 (eg. 1582-365 is invalid) and week numbers over 51 for that year.

@Voitcus No! This task is specifically about the proleptic Gregorian calendar. Otherwise the leap rule would also change to the simplistic Julian „every fourth year“ and the first day of the years had to be 1 March up—I don’t know when, furthermore there would probably be no year zero, but some strange affixes like AD or BCE. Let’s not do that this time.

Regex inherits from Method in Perl 6 so is itself a form of executable code.

PCRE (also Perl), 778 bytes
/^([+-]?\d*((([02468][048]|[13579][26]|\d\d(?!00))([02468][048]|[13579][26]))|\d{4}(?!-02-29|-366))-((?!02-3|(0[469]|11)-31|000)((0[1-9]|1[012])-(0[1-9]|[12]\d|30|31)|([012]\d\d|3([0-5]\d|6[0-6])))|(W(?!00)([0-4]\d|51|52)-[1-7]))|((\+?\d*([02468][048]|[13579][26])|-\d*([02468][159]|[13579][37]))(04|09|15|20|26|32|37|43|48|54|60|65|71|76|82|88|93|99)|(\+?\d*([02468][159]|[13579][37])|-\d*([02468][26]|[13579][048]))(05|11|16|22|28|33|39|44|50|56|61|67|72|78|84|89|95)|(\+?\d*([02468][26]|[13579][048])|-\d*([02468][37]|[13579][159]))(01|07|12|18|24|29|35|40|46|52|57|63|68|74|80|85|91|96)|\+?\d*(([02468][37]|[13579][159])(03|14|20|25|31|36|42|53|59|64|70|76|81|87|92|[049]8))|-\d*(([02468][048]|[13579][26])([059]2|08|13|19|24|30|36|41|47|58|64|69|75|80|86|97)))-W53-[1-7])$/

I have included the delimiters in the byte count to show that it doesn't rely on any flags.
It does not match valid dates within other strings, such as 1234-56-89    2016-02-29    9876-54-32. The regex is shorter by not checking for a maximum of 10 digits for the year.
Extended with comments:
/^  # Start of pattern (no leading space)
  (
    # YEAR
    # Optional sign and digits if more than 4 in year
    [+-]?\d*(
      # Years 00??, 04??, 08?? ... 92??, 96?? OR dd not followed by 00
      # followed by 00, 04, 08 ... 92, 96 OR
      (([02468][048]|[13579][26]|\d\d(?!00))([02468][048]|[13579][26])) |
      # any year not followed by 29 February or day 366
      \d{4}(?!-02-29|-366)
    # dash
    ) -
    # MONTH AND DAY, or DAY OF YEAR, or WEEK OF YEAR AND DAY if less than 53 weeks
    (
      # Not (30 or 31 February OR 31 April, June, September or December OR day 0)
      (?!02-3|(0[469]|11)-31|000)
      (
        # Month         dash         day         OR
        (0[1-9]|1[012]) - (0[1-9]|[12]\d|30|31) |
        # 001-299 OR 300-359 OR 360-366
        ([012]\d\d | 3([0-5]\d | 6[0-6]))
      # OR
      ) |
      (
        # W    01-52    dash    1-7
        W(?!00)([0-4]\d|51|52)-[1-7]
      )
    # OR
    ) |
    # WEEK OF YEAR AND DAY only if week is 53
    (
      # Optional plus and extra year digits
      \+?\d*(
        # Years +0303 - +9998
        ([02468][37]|[13579][159])(03|14|20|25|31|36|42|53|59|64|70|76|81|87|92|[049]8)
      ) |
      # Minus and extra year digits
      -\d*(
        # Years -0002 - -9697
        ([02468][048]|[13579][26])([059]2|08|13|19|24|30|36|41|47|58|64|69|75|80|86|97)
      ) |
      # Years +0004 - +9699, -0104 - -9799
      (\+?\d*([02468][048]|[13579][26])|-\d*([02468][159]|[13579][37]))
          (04|09|15|20|26|32|37|43|48|54|60|65|71|76|82|88|93|99) |
      # Years +0105 - +9795, -0205 - -9895
      (\+?\d*([02468][159]|[13579][37])|-\d*([02468][26]|[13579][048]))
          (05|11|16|22|28|33|39|44|50|56|61|67|72|78|84|89|95) |
      # Years +0201 - +9896, -0301 - -9996
      (\+?\d*([02468][26]|[13579][048])|-\d*([02468][37]|[13579][159]))
          (01|07|12|18|24|29|35|40|46|52|57|63|68|74|80|85|91|96)
    # dash W 53 dash 1-7
    )-W53-[1-7]
  # End of pattern (no trailing space)
  )$/x

I haven‘t checked everything yet, but it seems you gain the most bytes by (?!…) expressions compared to my solution.

@Crissov The (?!…) expressions only save a few bytes each. I reduced a lot of bytes by combining three of the positive/negative week-of-year/day-of-week year patterns into one each. The last ones don't correspond to each other. So I got 8 long sub-patterns down to 5. Also, since |20|25| is the same length as |2[05]| I went for the more readable option.

This expression matches the test case -0000-08-10 and doesn’t match ␠2015-08-10␠ with leading and trailing whitespace, but since both were arbitrary decisions or optional features I’ll let it slide.

I think this solution has a bug for dates within W50.

W(?!00)([0-4]\d|51|52)-[1-7] must be something equivalent to W(?!00)([0-4]\d|5[0-2])-[1-7]. This adds one character to the length. 779

@Crissov No, 51|52 matches 51 or 52. 5[0-2] matches 50, 51 or 52.

@Crissov If you think there's a bug, you should post an example that demonstrates the bug.

2018-W50-1 vs. 2018-W51-1 and 2018-W49-1

PCRE: 603 940 947 949 956 bytes
^\s*[+-]?(\d{4,10}-((00[1-9]|0[1-9]\d|[12]\d\d|3[0-5]\d|36[0-5])|(0[1-9]|1[0-2])-(0[1-9]|1\d|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31|W(0[1-9]|[1-4]\d|5[0-2])-[1-7]))|((\d{2,8}([13579][26]|[2468][048]|0[48])|(\d{0,6}([13579][26]|[02468][048])00))-(366|02-29))|(\+?\d{0,6}(([02468][048]|[13579][26])([26]0|71|[38]2|[49]3|[05]4|15|[27]6|37|[48]8|[09]9)|([02468][159]|[13579][37])(50|[16]1|[27]2|33|[48]4|[09]5|[15]6|67|[27]8|[38]9)|([02468][26]|[13579][048])([48]0|[09]1|[15]2|63|[27]4|[38]5|[49]6|[05]7|[16]8|29)|([02468][37]|[13579][159])([27]0|[38]1|[49]2|[05]3|[16]4|25|[37]6|87|[049]8|[5]9))|-\d{0,6}(([02468][048]|[13579][26])(0[28]|1[39]|24|3[06]|4[17]|5[28]|6[49]|75|8[06]|9[27])|([02468][159]|[13579][37])(0[49]|15|2[06]|3[27]|4[38]|54|6[05]|7[16]|8[28]|9[39])|([02468][26]|[13579][048])(0[51]|16|2[28]|3[39]|44|5[06]|6[17]|7[28]|8[49]|95)|([02468][37]|[13579][159])(0[17]|1[28]|2[49]|35|4[06]|5[27]|6[38]|74|8[05]|9[16])))-W53-[1-7]\s*$

Note: Some pairs of parentheses could possibly be dropped.

Test valid dates and formats
Test invalid dates
Test invalid formats

Divisibility by 4
The multiples of 4 repeat in a simple pattern:

00, 04, 08, 12, 16,
20, 24, 28, 32, 36,
40, 44, 48, 52, 56,
60, 64, 68, 72, 76,
80, 84, 88, 92, 96, …

This, or the inverse, could be matched by a likewise simple regular expression for all two-digit numbers with leading zero:
(?<divisible-by-four>[13579][26]|[02468][048])
(?<not-divisible-by-four>[13579][048]|[02468][26]|\d[13579])

It could save some bytes if there were character classes for odd and even digits (like \o and \e), but there are not as far as I’m aware.
Years
That expression would suffice for the Julian calendar, but the Gregorian leap year detection needs to special-case trailing 00 with century divisibility by 4:
(?<leap-year>[+-]?(\d{2,8}([13579][26]|[2468][048]|0[48])|(\d{0,6}([13579][26]|[02468][048])00))
(?<year>[+-]?\d{4,10})

This would need some changes to outlaw -0000-… (along with -00000-… etc.) or to enforce the plus sign for positive year numbers with more than 4 digits. The latter would be rather simple, but is not required:
(?<leap-year>([+-]?(\d\d([13579][26]|[2468][048]|0[48])|(([13579][26]|[02468][048])00)))|([+-](\d{3,8}([13579][26]|[2468][048]|0[48])|(\d{1,6}([13579][26]|[02468][048])00))))
(?<year>([+-]?\d{4})|([+-]\d{5,10}))

Day of year
Three-digit ordinal dates are rather simple, we just have to restrict -366 to leap years (and disallow -000).
(?<ordinal-day>-(00[1-9]|0[1-9]\d|[12]\d\d|3[0-5]\d|36[0-5]))
(?<ordinal-leap-day>-366)

Day of month of year
The seven months with 31 days are 01 January, 03 March, 05 May, 07 July, 08 August, 10 October and 12 December. Just four month have exactly 30 days, 04 April, 06 June, 09 September and 11 November. Finally, 02 February has 28 days in common years and 29 in leap years. We can first construct a regular expression for the always valid days 01 through 28 and then add special cases.
(?<month-day>-(0[1-9]|1[0-2])-(0[1-9]|1\d|2[0-8]))
(?<short-month-day>-(0[13-9]|1[0-2])-(29|30))
(?<long-month-day>-(0[13578]|1[02])-31)
(?<month-leap-day>-02-29)

Neither month nor day must be 00 which was not covered by an earlier version.
Day of week of year
All years include 52 weeks
(?<week-day>-W(0[1-9]|[1-4]\d|5[0-2])-[1-7])

Long years that include -W53 repeat in a 400-year cycle, e.g. add 2000 for the current cycle and find the current year in the third entry:

004, 009, 015, 020, 026, 032, 037, 043, 048, 054, 060, 065, 071, 076, 082, 088, 093, 099,
105, 111, 116, 122, 128, 133, 139, 144, 150, 156, 161, 167, 172, 178, 184, 189, 195,
201, 207, 212, 218, 224, 229, 235, 240, 246, 252, 257, 263, 268, 274, 280, 285, 291, 296,
303, 308, 314, 320, 325, 331, 336, 342, 348, 353, 359, 364, 370, 376, 381, 387, 392, 398.

Each of the four centuries has a unique pattern. There is probably not much room for optimization.

04|09|15|20|26|32|37|43|48|54|60|65|71|76|82|88|93|99
05|11|16|22|28|33|39|44|50|56|61|67|72|78|84|89|95
01|07|12|18|24|29|35|40|46|52|57|63|68|74|80|85|91|96
03|08|14|20|25|31|36|42|48|53|59|64|70|76|81|87|92|98

We can group by either digit to find out that we can save two bytes or so:

Grouped by 1st digit.

0[49]|15|2[06]|3[27]|4[38]|54|6[05]|7[16]|8[28]|9[39]
05|1[16]|2[28]|3[39]|44|5[06]|6[17]|7[28]|8[49]|95
0[17]|1[28]|2[49]|35|4[06]|5[27]|6[38]|74|8[05]|9[16]
0[38]|14|2[05]|3[16]|4[28]|5[39]|64|7[06]|8[17]|9[28]

Grouped by 2nd digit.

[26]0|71|[38]2|[49]3|[05]4|15|[27]6|37|[48]8|[09]9
50|[16]1|[27]2|33|[48]4|[09]5|[15]6|67|[27]8|[38]9
[48]0|[09]1|[15]2|63|[27]4|[38]5|[49]6|[05]7|[16]8|29
[27]0|[38]1|[49]2|[05]3|[16]4|25|[37]6|87|[049]8|[5]9

The century number is easily matched again by a variation of the divisibility expression.

1st century: [02468][048]|[13579][26]
2nd century: [02468][159]|[13579][37]
3rd century: [02468][26]|[13579][048]
4th century: [02468][37]|[13579][159]

So far, this does only work for positive years, including year zero. For negative years, we have to subtract the values from the list above from 400 and do the rest again, because the pattern is not symmetric.

02|08|13|19|24|30|36|41|47|52|58|64|69|75|80|86|92|97
04|09|15|20|26|32|37|43|48|54|60|65|71|76|82|88|93|99
05|11|16|22|28|33|39|44|50|56|61|67|72|78|84|89|95
01|07|12|18|24|29|35|40|46|52|57|63|68|74|80|85|91|96

or

0[28]|1[39]|24|3[06]|4[17]|5[28]|6[49]|75|8[06]|9[27]
0[49]|15|2[06]|3[27]|4[38]|54|6[05]|7[16]|8[28]|9[39]
0[51]|16|2[28]|3[39]|44|5[06]|6[17]|7[28]|8[49]|95
0[17]|1[28]|2[49]|35|4[06]|5[27]|6[38]|74|8[05]|9[16]

Putting it all together
Any year
[+-]?\d{4,10}-((00[1-9]|0[1-9]\d|[12]\d\d|3[0-5]\d|36[0-5])|(0[1-9]|1[0-2])-(0[1-9]|1\d|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31|W(0[1-9]|[1-4]\d|5[0-2])-[1-7])

Leap-day year additions
[+-]?(\d{2,8}([13579][26]|[2468][048]|0[48])|(\d{0,6}([13579][26]|[02468][048])00))-(366|02-29)

Leap-week year additions
+?\d{0,6}(([02468][048]|[13579][26])([26]0|71|[38]2|[49]3|[05]4|15|[27]6|37|[48]8|[09]9)|([02468][159]|[13579][37])(50|[16]1|[27]2|33|[48]4|[09]5|[15]6|67|[27]8|[38]9)|([02468][26]|[13579][048])([48]0|[09]1|[15]2|63|[27]4|[38]5|[49]6|[05]7|[16]8|29)|([02468][37]|[13579][159])([27]0|[38]1|[49]2|[05]3|[16]4|25|[37]6|87|[049]8|[5]9))-W53-[1-7]
-\d{0,6}(([02468][048]|[13579][26])(0[28]|1[39]|24|3[06]|4[17]|5[28]|6[49]|75|8[06]|9[27])|([02468][159]|[13579][37])(0[49]|15|2[06]|3[27]|4[38]|54|6[05]|7[16]|8[28]|9[39])|([02468][26]|[13579][048])(0[51]|16|2[28]|3[39]|44|5[06]|6[17]|7[28]|8[49]|95)|([02468][37]|[13579][159])(0[17]|1[28]|2[49]|35|4[06]|5[27]|6[38]|74|8[05]|9[16]))-W53-[1-7]

Your pattern is not anchored at the beginning and end, so it will match valid dates inside an otherwise invalid string.

@CJDennis That’s true, I’ll add the two characters now.

I’ve also added optional leading and trailing spaces \s*.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Counting Pages of a Book
Task
Given the page of a book P on stdin, count all occurrences of the digits 0-9 in each member of the range 1 to P. There is no page zero and your program should handle any number less than 1,000,000. Since putting a constraint on how you can do it is difficult to explain there will be a time limit of 3 seconds instead. That may be too short for some of the answers already submitted but mine runs faster than that so it is possible.
Examples (plus a list of the occurences):
input: 10

0 = 1  (10)
1 = 2  (1, 10)
2 = 1  (2)
3 = 1  (3)
4 = 1  (4)
5 = 1  (5)
6 = 1  (6)
7 = 1  (7)
8 = 1  (8)
9 = 1  (9)

input: 20

0 = 2  (10, 20)
1 = 11 (1, 10, 11 ... 18, 19)
2 = 3  (2, 12, 20)
3 = 2  (3, 13)
4 = 2  (4, 14)
5 = 2  (5, 15)
6 = 2  (6, 16)
7 = 2  (7, 17)
9 = 2  (8, 18)

"Your program is not allowed to loop through all the numbers and count the numbers on each." So what are we allowed to do? Can I loop through all numbers from 10 to N and add 1 to each count (provided N > 9)? Can I loop through chunks of the largest power of 10 less than N and then loop through all numbers in the smallest chunk?

@MartinBüttner There are ways of doing it without going to each page and getting the individual numbers in it. So if you were looping through all the pages up to 1000 and currently looking at page 865, you can't just pull out 8, 6, and 5. You need to find another way of doing it. Your method is just a rewording of what I said you can't do. Just because you're breaking the pages into chunks of ten doesn't make it any different.

Are you saying it can be done without any looping at all? I.e. in O(1)? Because if not, then my question is still valid: where do you draw the line between an allowed loop and a disallowed loop? Do you want O(log N) (in which case looping through chunks of powers of 10 would actually be valid)?

I think the issue, here, is that the restriction isn't well-defined. Are you saying that you're not allowed to iterate, or that you're not allowed to extract digits, or that you're not allowed to use both at once? Or is it something else that you specifically don't want? The restriction can't be a "I'll know it when I see it" kind of thing, it needs to be clear-cut.

I tried to update it to be more specific. Basically don't extract single digits. you should be doing some sort of calculation or cache checking or something else instead

Related

@PeterTaylor Definitely related but not quite the same. There's some seriously interesting answers in there

Instead of putting a vague restriction, you could ask the program to finish in predefined number of seconds, given very large numbers as input.

@metalim I thought of that but I wasn't sure how much time allot.

I lowered the largest test case since it wreaks havoc on my computer and I'm assuming others as well when it gets much higher than 1,000,000

Matlab, 43 bytes
y=hist(+num2str(1:input('')),47:57);y(2:11)

Example:
>> y=hist(+num2str(1:input('')),47:57);y(2:11)
10
ans =
     1     2     1     1     1     1     1     1     1     1

How it works:
1:input('') generates a vector of numbers from 1 to the input number.
num2str converts all those numbers to a space-separated string (char array).
The + converts from char to ASCII codes. Digits are 48 to 57 in ASCII.
hist counts how many times each of those ASCII codes appears. Actually the count for value 47 is necessary too, because hist collects all lower values in the first bin. So that 47 just intercepts all spaces and prevents them from being confused as zeroes.
Lastly, y(2:11) removes that first count and prints the result.

Do you mind explaining how it works?

@SirParselot Edited!

Very clever Luis! But 1:1e9 is a very long / large string! Can you run this for the maximum number of pages?

@StewieGriffin Thanks! Well, I can't. But that's because I have little RAM in my laptop. I guess it could be done on a modern computer

I've been running it from 1:999999 and its been going for a while, at least two minutes. However, I am using tutorialspoint online Matlab executor

You'd need about 21GB, since the number of spaces in between each digits increases for every factor of 10. Maybe one day I'll have one like that... You have my +1 anyway... Really like the solution!

@StewieGriffin Good point. Actually I didn't consider the maximum P in my answer

@StewieGriffin - Come join us in the MATLAB / Octave chat room whenever you have time :)! http://chat.stackoverflow.com/rooms/81987/matlab-and-octave

CJam, 18 14 10 bytes
Thanks @Dennis for a 4 bytes golf.
qi,:)s$e`p

Try it online.
Explanation
qi         e# Convert input to integer
  ,:)      e# Push [1 ... input]
     s     e# Convert to string (concats all numbers)
      $    e# Sort the string
       e`  e# Run-length encode
         p e# Print

,:) is shorter than ),0-. If [[2 '0] [12 '1]... is an acceptable output format, you can use run-length encoding $e`  to save three more bytes.

@Dennis Thanks. RLE feels so obvious now. You never cease to impress me ;)

K5, 43 bytes (27 without fancy output formatting)
`0:"\n"/($!10){x," = ",$#&y=*x}\:,/$1+!.0:`

Without formatting:
($!10){#&y=*x}\:,/$1+!. 0:`

Might not handle all numbers up to 1e9...(well, it could, with lots of memory).
Also, it's the same core algorithm as the Matlab answer. Ironically enough, I wrote this earlier this morning (before the Matlab answer), but then got distracted by Sonic 06 videos and forgot to post it... :(
Still cool.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Print a non-clashing binary search tree
Brief

Print an ASCII representation of a binary search tree.
You should write your own minimum implementation logic of a BST (node, left, right, insert)

(50,30,70,20,80,40,75,90) gives:

__50__70__80__90
   |       |
   |       |__75
   |
   |__30__40
       |
       |__20

Detailed requirements

Items are inserted into the tree in the order in which they are in the list
All node values are right aligned in columns.
Right nodes are joined using __
Right nodes are represented along the horizontal and appear directly to the right of the parent node
Right nodes are separated by a minimum of 2 underscores (__)
Left nodes are joined using | and |__ on the next line
Left nodes are represented along the vertical and appear under and to the right of the parent (ie, next column).
Left nodes are separated by a a minimum of a blank line (discounting pipes (|) linking child to parent)
The vertical pipes joining 2 left nodes should be in the column directly under the last character of the parent node (see samples)
Column width is determined using something like max(col_values[]).toString().length() + 2
Branching left always adds a new row to the tree diagram
2 separate (left) branches never appear on the same line (right__right__right is OK)
The root node may optionally be prefixed with __ (Removing it just about doubled my test code!)
Input is a set of positive and/or negative integers
You do not need to deal with duplicate values (drop/ignore them)
I'm not placing many restrictions on trailing whitespaces:

You may have trailing whitespaces after the last node on a line
You may have trailing whitespace after a | on the empty lines
No whitespace between nodes when when branching right

Standard loopholes and T&Cs apply
This is code-golf. Shortest code in bytes wins!

I'm aware that this is a potential duplicate, but I think I've been specific enough in my requirements that it should pose new challenges.
Sample Input/Output

Input
(50,40,30,20,10)

Output
__50
   |
   |__40
       |
       |__30
           |
           |__20
               |
               |__10

Input
(10,20,30,40,50)

Output
__10__20__30__40__50

Input
(50,700,30,800,60,4,5,10,20,2,500,850,900,950,870,35,1,-10)

Output
__50__700__800__850__900__950
   |    |              |
   |    |              |__870
   |    |
   |    |___60__500
   |
   |___30___35
        |
        |____4____5___10___20
             |
             |____2
                  |
                  |____1
                       |
                       |__-10

Related.

@MartinBüttner yup, that's the one I was trying to be different enough from!

Is this challenge too simple? Boring? Trivial? Uninteresting? Would appreciate some feedback so I can pose better challenges.

I don't think it's any of those. If anything the challenge is fairly hard. That's not a bad thing though, but it can mean that it receives less attention.

Hmm. Didn't think it was too hard - perhaps it's the nature of the problem. Some challenges seem (to me, at least) to be far more complicated and they receive a few answers.  No problem though. I enjoyed writing it and having to solve it too. Good exercise for myself.

Java 1286 1106 1100 bytes
Here's an easy entry to beat ;-)
Pretty messy. I traverse the tree, populating a 2d array with the node values (and left branch pipes), and a size array with the maximum column widths. Then print the node array using size array to determine correct horizontal spacing.  I look forward to seeing a better way of doing this.
class N{N l,r;int v,i,h,g,b,e,c,j;String[][]a=new String[10][10];int[]w=new int[10];String o="",p="";N(int x){v=x;}void i(int n){if(n>v)if(r==null)r=new N(n);else r.i(n);else if(n<v)if(l==null)l=new N(n);else l.i(n);}void p(N node){a[b][h]=""+node.v;if(w[h]<a[b][h].length())w[h]=a[b][h].length();if(node.r!=null){h++;p(node.r);h--;}if(node.l!=null){b++;while(g<b)a[++g][h]="|";h++;p(node.l);if(a[--g][--h].equals("|"))g--;}}void d(){for(e=-1;++e<a.length;){o="";for(j=-1;++j<a[0].length;){p=a[e][j];if(p!=null)if(p.equals("|")){for(i=0;i++<w[j]-p.length()+2;)o+=" "; o+=p;}else for(i=0;i++<w[j]+2;)o+=" ";else for(i=0;i++<=w[j]+1;)o+=" ";}if(!o.trim().equals(""))System.out.println(o);o="";for(c=-1;++c<a[0].length;){p=a[e][c];if(p!=null)if(p.equals("|")){for(i=0;i++<w[c]-p.length()+2;)o+=" ";o+=p;}else{for(i=0;i++<w[c]-p.length()+2;)o+="_"; o+=p; }else for(i=0;i++<=w[c]+1;)o+=" ";}if(!o.trim().equals(""))System.out.println(o);}}public static void main(String[]a){String[]q=a[0].split(",");N t=new N(Integer.parseInt(q[0]));for(int i=0;i++<q.length-1;)t.i(Integer.parseInt(q[i]));t.p(t);t.d();}}

__50__700__800__850__900__950
   |    |              |
   |    |              |__870
   |    |
   |    |___60__500
   |
   |___30___35
        |
        |____4____5___10___20
             |
             |____2
                  |
                  |____1
                       |
                       |__-10

Ungolfed

class N {
    N leftNode, rightNode;
    int index, loop, curRight, curDown, maxDown, row,col;
    String[][] nodes = new String[10][10];
    int[] colWidths = new int[10];
    String line = "", node="";
N(int index) {
    this.index = index;
}

void i(int newValue) {
    if (newValue > index) {
        if (rightNode == null) {
            rightNode = new N(newValue);
        }
        else {
            rightNode.i(newValue);
        }
    }
    else if (newValue < index) {
        if (leftNode == null) {
            leftNode = new N(newValue);
        }
        else {
            leftNode.i(newValue);
        }
    }
}

void p(N node) {
    // Push current node
    nodes[maxDown][curRight] = ""+node.index;
    // Keep track of max column widths
    if (colWidths[curRight] < nodes[maxDown][curRight].length()) {
        colWidths[curRight] = nodes[maxDown][curRight].length();
    }
    // Branch right
    if (node.rightNode != null) {
        curRight++;
        p(node.rightNode);
        curRight--;
    }
    // Branch left
    if (node.leftNode != null) {
        maxDown++;
        while (curDown<maxDown){
            nodes[++curDown][curRight] = "|";
        }
        curRight++;
        p(node.leftNode);
        if (nodes[--curDown][--curRight].equals("|")) { //following the ladder back up
            curDown--;
        }
    }
}

void d() {
    for ( row = -1; ++row < nodes.length;) {
        // Sloppy. Inject extra rows to extend pipes (double spacing)
        line = "";
        for (int col = -1; ++col < nodes[0].length;) {
            node = nodes[row][col];
            if (node!=null){
                if (node.equals("|")) {
                    for (loop=0; loop++< colWidths[col] - node.length() + 2; ){
                        line+=" ";
                    }
                    line+=node;
                }
                else {
                    for (loop=0; loop++< colWidths[col]  + 2;){
                        line+=" ";
                    }
                }
            }
            else {
                for (loop=0; loop++<=colWidths[col]+1;){
                    line+=" ";
                }
            }
        }
        if (!line.trim().equals("")){
            System.out.println(line);
        }
        line="";

        for ( col = -1; ++col < nodes[0].length;) {
            node = nodes[row][col];
            if (node!=null){
                if (node.equals("|")) {
                    for (loop=0; loop++< colWidths[col] - node.length() + 2;){
                        line+=" ";
                    }
                    line+=node;
                }
                else {
                    for (loop=0; loop++< colWidths[col] - node.length() + 2;){
                        line+="_";
                    }
                    line+=node;
                }
            }
            else {
                for (loop=0; loop++<=colWidths[col]+1;){
                    line+=" ";
                }
            }
        }
        if (!line.trim().equals("")){
            System.out.println(line);
        }
    }
}

public static void main(String[]a){
    String[] values = a[0].split(",");
    N t=new N(Integer.parseInt(values[0]));
    for (int i=0;i++<values.length-1;)
    t.i(Integer.parseInt(values[i]));
    t.p(t);
    t.d();
}
}


text:
Giving Directions
Challenge
You've given a map to a friend that looks a bit like this:
      |
      /
     |
     /
    |
    \
     |
     \
      D

A simple map that starts at the top and ends at the bottom.
Sadly, your friend doesn't get it. Can you decode the map so that he can read it?
Input
The input is a string of characters consisting of |, /, \, D, ^, Y,  (space), and newlines.

| tells to stay in the same column.
\ tells to move to the column to the right and down 1.
/ tells to move to the column to the left and down 1.
D marks the destination.

^ (if present) tells of a split in the path.
Y (if present) tells of a rejoining of paths. Treat it like a |.

The input will be arranged so that it makes a kind of path:
   |
   |
   \
    |
    ^
   / \
  /   |
 D    |

There will always be a space between two paths, and all paths will either rejoin or reach the last line of the input. There will only be one split per map.
There is no limit to the length of the input map.
There will never be more than two paths.
Output
The output should be a string of directions.

"L" should tell your friend to move Left and take 1 step forward.
"R" should tell your friend to move Right and take 1 step forward.
"F" should tell your friend to move 1 step forward.

For the input example map, the output would be as follows:
F F L F R R R

Note that your friend is starting at the top of the map and facing down the map. Give the directions from his perspective.
For an instance of "^", your program must be able to choose the path that leads to the destination (D). If the two paths recombine, your program must choose the straightest path (the one with the most |s) to follow.
Directions must be separated by spaces, and must end on D.
Examples
Input
      |
      |
      \
       \
        ^
       / |
      |  |
      \  |
       \ \
        \ \
         \ /
          Y
          D

Output
F F L L L F F F L L R F

Since the leftmost path contains only 1 |, we use the rightmost path that has 3.

Input
\
 |
 /
|
\
 |
 /
D

Output
L F R F L F R

Input
    /
   \
    /
   \
    ^
   \ \
    D \

Output
R L R L R L

Other details

This is code golf, so the person with the shortest code by next Wednesday, the 19th of August, wins.
Constructive feedback welcome and greatly appreciated.
Partially inspired by A Map to Hidden Treasure
Feel free to change the title to something more creative.
If you find mistakes that I made, correct them.
And of course, have fun.

Thank you!
A bit late, maybe, but UndefinedFunction is the winner coding in JavaScript! Thanks to all who entered. No other entries will be accepted.

It still seems off. The first example ends in L L, which I think should be L L L. The example with Y still has a 1 at the end and also seems to have other errors. I read the map as F F R R R F F F R R L F if I understand the rules correctly.

@MartinBüttner you're supposed to end on D, you would only need 2 Ls. 3 Ls would go past D.

Can a path ever reach a dead end before reaching the last line? Or will all paths reach the last line of the input?

@BassetHound shouldn't there be one L for the ^ and two L for the two /? And why did you add two more F to the end of the Y example?

@ETHproductions Yes.

@UndefinedFunction All second paths will reach the bottom of the input.

Is it possible to have more than one split, each of them paired with a join before the next split? For example: http://pastebin.com/raw.php?i=vCyX4q17 Its output should be F R F F F L F F F

@axiac That was not my intention, so there will only be one (if any) split.

Javascript (ES6), 261 248 252 248 212 bytes
Since only one split has to be supported:
s=>(s=s.replace(/ /g,o="",d=0).split(`
`)).map((v,j)=>{if(v=="^")for(v="/\\";(w=s[++j])&&(x=w[1]);d=x=="D"?1:w[0]=="D"?0:x>"{"?d+1:w[0]>"{"?d-1:d);o+=(p=v[d>0?1:0]||v[0])<"0"?"R ":p<"E"?"":p=="\\"?"L ":"F "})?o:o

However, 240 bytes and we can deal with multiple splits:
s=>(s=s.replace(/ /g,o="").split(`
`)).map((v,j)=>{if(!v[1])t=d=0
else if(!t){for(t=1;(w=s[++j])&&(x=w[1]);d=x=="D"?1:w[0]=="D"?0:x>"{"?d+1:w[0]>"{"?d-1:d);o+=d>0?"L ":"R "}o+=(p=v[d>0?1:0])<"0"?"R ":p<"E"||p=="^"?"":p=="\\"?"L ":"F "})?o:o

Both programs define anonymous functions.
To use, give the function(s) a name by adding f= before the code.
Afterwards, they can be called with
alert(f(
`   |
   |
   \\
    |
    ^
   / \\
  /   |
 D    |`
))

Explanation
(outdated, but still the same concept. For the multiple split solution)
s=>
    //Remove all spaces from the input
    (s=s.replace(/ /g,o="",
                 //Define function c, to convert symbols to directions
                 c=p=>p<"0"?"R ":p<"E"||p=="^"?"":p=="\\"?"L ":"F "
    //Split input into an array by newlines
    ).split(`
`))
    //for each string v in the input array, at index j:
    .map((v,j)=>{
        //if v is only one character long:
        if(!v[1]){
            t=1     //assign t to 1 (true) - we need to test if multiple paths
            d=0     //assign d to 0 - reset the counter for determining shortest path
        }
        //if v is two characters long, and we have not tested which path is shorter yet:
        else if(t){
            for(    t=0;    //assign t to 0 - we will have tested which path is longer

                    //for each string left in the input, while the input still has two characters:
                    (w=s[++j]) && w[1];
                    //assign d to determine which direction to go. This will be conveyed by if d>0
                    d=
                        w[1]=="D"?1:    //if the dest. is only on one side, choose that side.
                        w[0]=="D"?0:
                        w[1]=="|"?d+1:  //otherwise add/subtract from d (like a tug of war) to determine which side has more "|"
                        w[0]=="|"?d-1:
                        d
               );
            o+=d>0?"L ":"R "    //append to the output which direction was taken
        }

        o+=c(v[d>0?1:0])    //append to the output the characters from the correct path in any case, determined by d calculated above
                            //(or defaulting to 0, if path is not split, in which case the only character is appended)

    }) ? o : o  //coerce the result, which will evaluate to an array of the input, to the output (o) and implicitly return

Notes

All backslashes (\) in the input are escaped as \\, so that javascript can recognize them.
Both outputs contain a trailing space.

Dang it, thought I had it all fixed.

PHP, 634 631 607 396 382 381 347 338 330 337 324 bytes
My first ever golf so be gentle.
Any tips are greatly appreciated.
<?php
foreach(str_split(strtr(fgets(STDIN),[' '=>'']))as $i){if($i!=D){$z=$i=='^';$x=$i==Y;$s=!$z&&!$x?($i=='/'?R:($i=='|'?F:($i=='\\'?L:$s))):$s;$a.=$z?R:($x?F:(($c==1||!$c)?$s:''));$b.=$z?L:($x?F:(($c==2||!$c)?$s:''));$c=$z?1:($x?0:($c==1?2:($c==2?1:$c)));}else{echo(substr_count($a,F)<substr_count($b,F)&&$c==0||$c==2)?$b:$a;}}

Short Explanation:

I have a count which is 0 if the Input has only one path. When the path splits the count is 1 for the left path and 2 for the right path. After defining both paths (or only one) I check which path has more "F's".

Ungolfed Version:

<?php
$input = fgets(STDIN);
$inputArray = str_split($input);
foreach ($inputArray as $currentChar) {
    if ($currentChar != 'D') {
        if ($i == '^') {
            $firstPath .= 'R';
            $secondPath .= 'L';
            $count = 1;
        } elseif ($i == 'Y') {
            $secondPath .= 'F';
            $firstPath .= 'F';
            $count = 0;
        } else {
            if ($i == ' ') {
                continue;
            }
            if ($i == '/') {
                $direction = 'R';
            } else {
                if ($i == '|') {
                    $direction = 'F';
                } else {
                    if ($i == '\\') {
                        $direction = 'L';
                    } else {
                        $direction = '';
                    }
                }
            }
            if ($count == 1) {
                $firstPath .= $direction;
                $count = 2;
            } elseif ($count == 2) {
                $secondPath .= $direction;
                $count = 1;
            }
            if (!$count) {
                $firstPath .= $direction;
                $secondPath .= $direction;
            }
        }
    } else {
        echo (substr_count($firstPath, 'F') < substr_count($secondPath, 'F')) || $count == 2 ? $secondPath : $firstPath;
    }
};

Log:

Saved 36 Bytes thanks to Kamehameha.

Saved many many bytes by changing the logic a bit.

Saved 42 Bytes thanks to axiac.

Replaced every if statment with ternary operators.

Welcome to the site!

You can try $a=$b=''; instead of - $a='';$b=''; Saves around 3 bytes.

Also, concatenation like $a=$a.'L '; can be reduced to $a.='L '. You seem to have done that in a couple of places. That'll save around 6 bytes :)

I don't know PHP very well, but I believe you can drop the space after "as" in your foreach (foreach($e as$i)); I have tested that and it appears to work fine.

A couple more tips to save a few bytes, as @ProgramFox mentioned about the as in the foreach, the spaces between echo and the variable name can be removed to so you have echo$b. Also, a couple of equality tests can be shorter too, $c==0 could be !$c and if that's the case, you can initialise $c to '' with $a and $b!

Thanks for the tips! I changed quite a few things... I will edit the ungolfed Version soon to clear things up!

You can still save a dozen of bytes or more: eliminate the intermediate variables $e and $f (they are initialized then used only once); use D (constant) instead of 'D' (string); PHP will complain about not finding the constant D and will use the string 'D' instead; you can suppress the notices by invoking PHP from the command line as php -d error_reporting=0 script.php.

You can try replacing if($i=='\\')$s=L;else $s=''; with this - $s=($i=='\\')?L:$s;. Saves 10 bytes.

Hmm... fgets(STDIN) reads only the first line. The program doesn't output anything.

@axiac If you copy paste the examples from the question it will output the expected result. If you want to try your own example you need to use white spaces instead of line breaks.

I copy-pasted the first example and it came out with newlines. You should provide an example of usage. I run the code now using: cat 1.txt | tr '\n', ' ' | php -d error_reporting=0 script.php and it works.

Ten more bytes: 1) don't count the trailing newline (your current code has 337 bytes); 2) remove the space before as in fgets(STDIN)) as$i; 3) remove the empty statement at the end of the program (the very last semicolon); 4-7) remove the braces from else{if($i=='|')$s=F;else{$s=($i=='\\')?L:$s;}}; 8-10) remove if($i==' ')continue; and use strtr() to remove the whitespaces from the input instead: foraeach(str_split(strtr(fgets(STDIN),[' '=>'']))as$i).

@axiac Thanks for the help. I just removed the last semicolon of the script. Did you mean it that way? ... I will add an example of usage for my code soon.

Nicely done! I'd help, but I don't know PHP.

PHP, 281 bytes
$b=0;$p=['|'=>'$a[$b].="F ";$f[$b]++;','/'=>'$a[$b].="R ";','\\'=>'$a[$b].="L ";','^'=>'$d.=$a[0];$n=2;$a=["R ","L "];$f=[];$b=1;','Y'=>'$d.=$a[$f[0]<$f[$n=1]]."F ";$a=[];','D'=>'$d.=$a[$b];exit(rtrim($d));'];foreach(str_split($argv[$n=1])as$c){if($x=$p[$c]){eval($x);$b=++$b%$n;}}

It is the result of two golfing iterations. The ungolfed version is:
$a=$f=[];       // these assignments are not required (they were suppresed in v2)
$n=1;           // this assignment can be squeezed into $argv[$n=1]
$b=0;           // if this assignment is suppressed $b becomes '' and breaks the logic
$code = [
    '|' => '$a[$b].="F ";$f[$b]++;',
    '/' => '$a[$b].="R ";',
    '\\'=> '$a[$b].="L ";',
    '^' => '$d.=$a[0];$n=2;$a=["R ","L "];$f=[];$b=1;',
    'Y' => '$d.=$a[$f[0]<$f[$n=1]]."F ";$a=[];',
    'D' => '$d.=$a[$b];echo(rtrim($d));',
];
foreach (str_split($argv[1]) as $char) {
    // ignore input characters not in the keys of $code
    if ($x = $code[$char]) {
        eval($x);
        $b = ++ $b % $n;   // cycles between 0 and 1 ($n == 2) or stays 0 ($n == 1)
    }
}

It is pretty golfed itself and it emerged as an improvement of the following golfed program (312 bytes):
$b=0;foreach(str_split($argv[$n=1])as$c){if($c=='|'){$a[$b].='F ';$f[$b]++;}elseif($c=='/'){$a[$b].='R ';}elseif($c=='\\'){$a[$b].='L ';}elseif($c=='^'){$d.=$a[0];$n=2;$a=['R ','L '];$f=[];$b=1;}elseif($c==Y){$d.=$a[$f[0]<$f[$n=1]].'F ';$a=[];}elseif($c==D){$d.=$a[$b];exit(rtrim($d));}else continue;$b=++$b%$n;}

It is the golfed version of the original:
$map = $argv[1];

$dir = '';              // the already computed directions
$nb = 1;                // the number of branches
$branches = [ '' ];     // the branches (2 while between '^' and 'Y', 1 otherwise)
$nbF = [ 0, 0 ];        // the number of 'F's on the branches (used to select the branch)
$curr = 0;              // the current branch
foreach (str_split($map) as $char) {
    if ($char == '|') {             // go 'F'orward
        $branches[$curr] .= 'F ';       // put it to the current branch
        $nbF[$curr] ++;                 // count it for the current branch
    } elseif ($char == '/') {       // go 'R'ight
        $branches[$curr] .= 'R ';
    } elseif ($char == '\\') {      // go 'L'eft
        $branches[$curr] .= 'L ';
    } elseif ($char == '^') {       // fork; choose the path ('L' or 'R') that contains the most 'F'orward segments
        $dir .= $branches[0];           // flush the current path (it was stored as the first branch)
        $nb = 2;                        // start two branches
        $branches = [ 'R ', 'L ' ];     // put the correct directions on each branch
        $nbF = [ 0, 0 ];                // no 'F's on any branch yet
        $curr = 1;                      // need this to let it be 0 on the next loop
    } elseif ($char == 'Y') {       // join
        $dir .= $branches[$nbF[0] < $nbF[1]];   // flush; choose the branch having the most 'F's
        $dir .= 'F ';                           // treat it like a "|"
        $branches = [ '' ];                     // back to a single, empty branch
        $nb = 1;
    } elseif ($char == 'D') {       // finish
        $dir .= $branches[$curr];       // flush
        break;                          // and exit; could use 'return' but it's one byte longer; use exit() in the final program and save 5 bytes
    } else {
        continue;
    }
    $curr = ++ $curr % $nb;
}
echo rtrim($dir);

Example execution:
$ php -d error_reporting=0 directions.php '
      |
      |
      \
       \
        ^
       / |
      |  |
      \  |
       \ \
        \ \
         \ /
          Y
          D
'; echo
F F L L L F F F L L R F
$

It also handles multiple forks correctly (need to join before the next fork in order to have at most two branches any time). I asked about multiple forks in a comment but the code was already done when the answer ("not needed") came.
The complete code with test suite and more comments can be found on github.

Wow good job! I still need to learn quite a few things!