⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gram.js

📁 一个类似windows
💻 JS
📖 第 1 页 / 共 5 页
字号:
/*
 * Grammar components.
 * Copyright (c) 1998 New Generation Software (NGS) Oy
 *
 * Author: Markku Rossi <mtr@ngs.fi>
 */

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 */

/*
 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/gram.js,v $
 * $Id: gram.js 21681 2006-04-21 15:00:24Z peterw $
 */

/* General helpers. */

function JSC$gram_reset ()
{
  JSC$label_count = 1;
  JSC$cont_break = new JSC$ContBreak ();
}


function JSC$alloc_label (num_labels)
{
  JSC$label_count += num_labels;

  return JSC$label_count - num_labels;
}


function JSC$format_label (num)
{
  return ".L" + num.toString ();
}


function JSC$count_locals_from_stmt_list (list)
{
  var i;

  /* First, count how many variables we need at the toplevel. */
  var lcount = 0;
  for (i = 0; i < list.length; i++)
    lcount += list[i].count_locals (false);

  /* Second, count the maximum amount needed by the nested blocks. */
  var rmax = 0;
  for (i = 0; i < list.length; i++)
    {
      var rc = list[i].count_locals (true);
      if (rc > rmax)
	rmax = rc;
    }

  return lcount + rmax;
}

/*
 * The handling of the `continue' and `break' labels for looping
 * constructs.  The variable `JSC$cont_break' holds an instance of
 * JSC$ContBreak class.  The instance contains a valid chain of
 * looping constructs and the currently active with and try testing
 * levels.  The actual `continue', `break', and `return' statements
 * investigate the chain and generate appropriate `with_pop' and
 * `try_pop' operands.
 *
 * If the instance variable `inswitch' is true, the continue statement
 * is inside a switch statement.  In this case, the continue statement
 * must pop one item from the stack.  That item is the value of the
 * case expression.
 */

function JSC$ContBreakFrame (loop_break, loop_continue, inswitch, label, next)
{
  this.loop_break = loop_break;
  this.loop_continue = loop_continue;
  this.inswitch = inswitch;
  this.label = label;
  this.next = next;

  this.with_nesting = 0;
  this.try_nesting = 0;
}


function JSC$ContBreak ()
{
  this.top = new JSC$ContBreakFrame (null, null, false, null);
}

new JSC$ContBreak ();

function JSC$ContBreak$push (loop_break, loop_continue, inswitch, label)
{
  this.top = new JSC$ContBreakFrame (loop_break, loop_continue, inswitch,
				     label, this.top);
}
JSC$ContBreak.prototype.push = JSC$ContBreak$push;

function JSC$ContBreak$pop ()
{
  if (this.top == null)
    error ("jsc: internal error: continue-break stack underflow");

  this.top = this.top.next;
}
JSC$ContBreak.prototype.pop = JSC$ContBreak$pop;

/*
 * Count the currently active `try' nesting that should be removed on
 * `return' statement.
 */
function JSC$ContBreak$try_return_nesting ()
{
  var f;
  var count = 0;

  for (f = this.top; f; f = f.next)
    count += f.try_nesting;

  return count;
}
JSC$ContBreak.prototype.try_return_nesting = JSC$ContBreak$try_return_nesting;

/*
 * Count currently active `with' nesting that should be removed on
 * `continue' or `break' statement.
 */
function JSC$ContBreak$count_with_nesting (label)
{
  var f;
  var count = 0;

  for (f = this.top; f; f = f.next)
    {
      count += f.with_nesting;
      if (label)
	{
	  if (f.label == label)
	    break;
	}
      else
	if (f.loop_continue)
	  break;
    }
  return count;
}
JSC$ContBreak.prototype.count_with_nesting = JSC$ContBreak$count_with_nesting;

/*
 * Count the currently active `try' nesting that should be removed on
 * `continue' or `break' statement.
 */
function JSC$ContBreak$count_try_nesting (label)
{
  var f;
  var count = 0;

  for (f = this.top; f; f = f.next)
    {
      count += f.try_nesting;
      if (label)
	{
	  if (f.label == label)
	    break;
	}
      else
	if (f.loop_continue)
	  break;
    }
  return count;
}
JSC$ContBreak.prototype.count_try_nesting = JSC$ContBreak$count_try_nesting;

function JSC$ContBreak$count_switch_nesting (label)
{
  var f;
  var count = 0;

  for (f = this.top; f; f = f.next)
    {
      if (f.inswitch)
	count++;
      if (label)
	{
	  if (f.label == label)
	    break;
	  }
      else
	if (f.loop_continue)
	  break;
    }
  return count;
}
JSC$ContBreak.prototype.count_switch_nesting
  = JSC$ContBreak$count_switch_nesting;

function JSC$ContBreak$get_continue (label)
{
  var f;

  for (f = this.top; f; f = f.next)
    if (label)
      {
	if (f.label == label)
	  return f.loop_continue;
      }
    else
      if (f.loop_continue)
	return f.loop_continue;

  return null;
}
JSC$ContBreak.prototype.get_continue = JSC$ContBreak$get_continue;

function JSC$ContBreak$get_break (label)
{
  var f;

  for (f = this.top; f; f = f.next)
    if (label)
      {
	if (f.label == label)
	  return f.loop_break;
      }
    else
      if (f.loop_break)
	return f.loop_break;

  return null;
}
JSC$ContBreak.prototype.get_break = JSC$ContBreak$get_break;

function JSC$ContBreak$is_unique_label (label)
{
  var f;

  for (f = this.top; f; f = f.next)
    if (f.label == label)
      return false;

  return true;
}
JSC$ContBreak.prototype.is_unique_label = JSC$ContBreak$is_unique_label;

JSC$cont_break = null;


/* Function declaration. */

function JSC$function_declaration (ln, lbrace_ln, name, name_given, args,
				   block, use_arguments_prop)
{
  this.linenum = ln;
  this.lbrace_linenum = lbrace_ln;
  this.name = name;
  this.name_given = name_given;
  this.args = args;
  this.block = block;
  this.use_arguments_prop = use_arguments_prop;
  this.asm = JSC$function_declaration_asm;
}

function JSC$function_declaration_asm ()
{
  var i, a;

  /* Define arguments. */
  JSC$ns.push_frame ();

  for (i = 0, a = 2; i < this.args.length; i++, a++)
    JSC$ns.define_symbol (this.args[i], JSC$SCOPE_ARG, a, this.linenum);

  /* Define the function name to be a global symbol. */
  new JSC$ASM_symbol (this.linenum, this.name).link ();

  /* Check that function gets the required amount of arguments. */
  new JSC$ASM_load_arg (this.lbrace_linenum, 1).link ();
  new JSC$ASM_add_2_i (this.lbrace_linenum).link ();
  new JSC$ASM_min_args (this.lbrace_linenum, this.args.length + 2).link ();

  /* Count how many local variables we need. */
  var num_locals = JSC$count_locals_from_stmt_list (this.block);

  /* Is the `arguments' property of function instance used? */
  if (this.use_arguments_prop)
    num_locals++;

  if (num_locals > 0)
    {
      new JSC$ASM_locals (this.lbrace_linenum, num_locals).link ();
      if (this.use_arguments_prop)
	{
	  /*
	   * Create an array for the arguments array and store it to
	   * the first local variable.
	   */
	  var ln = this.lbrace_linenum;
	  var locn = JSC$ns.alloc_local ();
	  JSC$ns.define_symbol ("arguments", JSC$SCOPE_LOCAL, locn, ln);

	  new JSC$ASM_const_i0 (ln).link ();
	  new JSC$ASM_load_global (ln, "Array").link ();
	  new JSC$ASM_new (ln).link ();
	  new JSC$ASM_swap (ln).link ();
	  new JSC$ASM_apop (ln, 2).link ();
	  new JSC$ASM_store_local (ln, locn).link ();

	  /* Push individual argumens to the array. */

	  /* Init the loop counter. */
	  new JSC$ASM_const_i0 (ln).link ();

	  var l_loop = new JSC$ASM_label ();
	  var l_out = new JSC$ASM_label ();

	  l_loop.link ();

	  /* Check if we'r done. */
	  new JSC$ASM_dup (ln).link ();
	  new JSC$ASM_load_arg (ln, 1).link ();
	  new JSC$ASM_cmp_ge (ln).link ();
	  new JSC$ASM_iftrue_b (ln, l_out).link ();

	  /* Load the nth argument to the top of the stack. */
	  new JSC$ASM_dup (ln).link ();
	  new JSC$ASM_add_2_i (ln).link ();
	  new JSC$ASM_load_nth_arg (ln).link ();

	  /* Push it to the array. */
	  new JSC$ASM_const_i1 (ln).link ();
	  new JSC$ASM_load_local (ln, locn).link ();
	  new JSC$ASM_call_method (ln, "push").link ();
	  new JSC$ASM_pop_n (ln, 4).link ();

	  /* Increment loop counter and continue. */
	  new JSC$ASM_add_1_i (ln).link ();
	  new JSC$ASM_jmp (ln, l_loop).link ();

	  /* We'r done. */
	  l_out.link ();

	  /* Pop the loop counter. */
	  new JSC$ASM_pop (ln).link ();
	}
    }

  /* Assembler for our body. */
  for (i = 0; i < this.block.length; i++)
    this.block[i].asm ();

  /*
   * Every function must return something.  We could check if all
   * control flows in this function ends to a return, but that would
   * bee too hard...  Just append a return const_undefined.  The optimizer
   * will remove it if it is not needed.
   */
  var ln;
  if (this.block.length > 0)
    ln = this.block[this.block.length - 1].linenum;
  else
    ln = this.linenum;

  new JSC$ASM_const_undefined (ln).link ();
  new JSC$ASM_return (ln).link ();

  /* Pop our namespace. */
  JSC$ns.pop_frame ();
}


function JSC$zero_function ()
{
  return 0;
}


/*
 * Statements.
 */

/* Block. */

function JSC$stmt_block (ln, list)
{
  this.stype = JSC$STMT_BLOCK;
  this.linenum = ln;
  this.stmts = list;
  this.asm = JSC$stmt_block_asm;
  this.count_locals = JSC$stmt_block_count_locals;
}

function JSC$stmt_block_asm ()
{
  JSC$ns.push_frame ();

  /* Assembler for our stmts. */
  var i;
  for (i = 0; i < this.stmts.length; i++)
    this.stmts[i].asm ();

  JSC$ns.pop_frame ();
}


function JSC$stmt_block_count_locals (recursive)
{
  if (!recursive)
    return 0;

  return JSC$count_locals_from_stmt_list (this.stmts);
}

/* Function declaration. */

function JSC$stmt_function_declaration (ln, container_id, function_id,
					given_id)
{
  this.stype = JSC$STMT_FUNCTION_DECLARATION;
  this.linenum = ln;
  this.container_id = container_id;
  this.function_id = function_id;
  this.given_id = given_id;
  this.asm = JSC$stmt_function_declaration_asm;
  this.count_locals = JSC$zero_function;
}

function JSC$stmt_function_declaration_asm ()
{
  new JSC$ASM_load_global (this.linenum, this.function_id).link ();
  new JSC$ASM_load_global (this.linenum, this.container_id).link ();
  new JSC$ASM_store_property (this.linenum, this.given_id).link ();
}

/* Empty */

function JSC$stmt_empty (ln)
{
  this.stype = JSC$STMT_EMPTY;
  this.linenum = ln;
  this.asm = JSC$stmt_empty_asm;
  this.count_locals = JSC$zero_function;
}

function JSC$stmt_empty_asm ()
{
  /* Nothing here. */
}


/* Continue. */

function JSC$stmt_continue (ln, label)
{
  this.stype = JSC$STMT_CONTINUE;
  this.linenum = ln;
  this.label = label;
  this.asm = JSC$stmt_continue_asm;
  this.count_locals = JSC$zero_function;
}

function JSC$stmt_continue_asm ()
{
  var l_cont = JSC$cont_break.get_continue (this.label);

  if (l_cont == null)
    {
      if (this.label)
	error (JSC$filename + ":" + this.linenum.toString ()
	       + ": label `" + this.label
	       + "' not found for continue statement");
      else
	error (JSC$filename + ":" + this.linenum.toString ()
	       + ": continue statement not within a loop");
    }

  var nesting = JSC$cont_break.count_with_nesting (this.label);
  if (nesting > 0)
    new JSC$ASM_with_pop (this.linenum, nesting).link ();

  nesting = JSC$cont_break.count_try_nesting (this.label);
  if (nesting > 0)
    new JSC$ASM_try_pop (this.linenum, nesting).link ();

  nesting = JSC$cont_break.count_switch_nesting (this.label);
  if (nesting > 0)
    {
      /* Pop the value of the switch expression. */
      if (nesting == 1)
	new JSC$ASM_pop (this.linenum).link ();
      else
	new JSC$ASM_pop_n (this.linenum, nesting).link ();
    }

  new JSC$ASM_jmp (this.linenum, l_cont).link ();
}


/* Break. */

function JSC$stmt_break (ln, label)
{
  this.stype = JSC$STMT_BREAK;
  this.linenum = ln;
  this.label = label;
  this.asm = JSC$stmt_break_asm;
  this.count_locals = JSC$zero_function;
}

function JSC$stmt_break_asm ()
{
  var l_break = JSC$cont_break.get_break (this.label);

  if (l_break == null)
    {
      if (this.label)
	error (JSC$filename + ":" + this.linenum.toString ()
	       + ": label `" + this.label
	       + "' not found for break statement");
      else
	error (JSC$filename + ":" + this.linenum.toString()
	       + ": break statement not within a loop or switch");
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -